| Directory: | ./ |
|---|---|
| File: | storage/innobase/fil/fil0fil.cc |
| Date: | 2022-12-13 11:44:05 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 3605 | 4479 | 80.5% |
| Branches: | 3087 | 6533 | 47.3% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /***************************************************************************** | ||
| 2 | |||
| 3 | Copyright (c) 1995, 2022, Oracle and/or its affiliates. | ||
| 4 | |||
| 5 | This program is free software; you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License, version 2.0, | ||
| 7 | as published by the Free Software Foundation. | ||
| 8 | |||
| 9 | This program is also distributed with certain software (including | ||
| 10 | but not limited to OpenSSL) that is licensed under separate terms, | ||
| 11 | as designated in a particular file or component or in included license | ||
| 12 | documentation. The authors of MySQL hereby grant you an additional | ||
| 13 | permission to link the program and your derivative works with the | ||
| 14 | separately licensed software that they have included with MySQL. | ||
| 15 | |||
| 16 | This program is distributed in the hope that it will be useful, | ||
| 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | GNU General Public License, version 2.0, for more details. | ||
| 20 | |||
| 21 | You should have received a copy of the GNU General Public License | ||
| 22 | along with this program; if not, write to the Free Software | ||
| 23 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 24 | |||
| 25 | *****************************************************************************/ | ||
| 26 | |||
| 27 | /** @file fil/fil0fil.cc | ||
| 28 | The tablespace memory cache */ | ||
| 29 | |||
| 30 | #include "my_config.h" | ||
| 31 | |||
| 32 | #include "detail/fil/open_files_limit.h" | ||
| 33 | |||
| 34 | #include <errno.h> | ||
| 35 | #include <fcntl.h> | ||
| 36 | #include <sys/types.h> | ||
| 37 | #include <scope_guard.h> | ||
| 38 | |||
| 39 | #include "mysqld.h" // server_uuid | ||
| 40 | |||
| 41 | #include "arch0page.h" | ||
| 42 | #include "btr0btr.h" | ||
| 43 | #include "buf0buf.h" | ||
| 44 | #include "buf0flu.h" | ||
| 45 | #include "dict0boot.h" | ||
| 46 | #include "dict0dd.h" | ||
| 47 | #include "dict0dict.h" | ||
| 48 | #include "fsp0file.h" | ||
| 49 | #include "fsp0fsp.h" | ||
| 50 | #include "fsp0space.h" | ||
| 51 | #include "fsp0sysspace.h" | ||
| 52 | #include "ha_prototypes.h" | ||
| 53 | #include "hash0hash.h" | ||
| 54 | #include "log0buf.h" | ||
| 55 | #include "log0chkp.h" | ||
| 56 | #include "log0recv.h" | ||
| 57 | #include "log0write.h" | ||
| 58 | #include "mach0data.h" | ||
| 59 | #include "mem0mem.h" | ||
| 60 | #include "mtr0log.h" | ||
| 61 | #include "my_dbug.h" | ||
| 62 | #include "ut0new.h" | ||
| 63 | |||
| 64 | #include "clone0api.h" | ||
| 65 | #include "os0file.h" | ||
| 66 | #include "page0zip.h" | ||
| 67 | #include "sql/mysqld.h" // lower_case_file_system | ||
| 68 | #include "srv0srv.h" | ||
| 69 | #include "srv0start.h" | ||
| 70 | |||
| 71 | #include "fil0crypt.h" | ||
| 72 | |||
| 73 | #ifndef UNIV_HOTBACKUP | ||
| 74 | #include "buf0lru.h" | ||
| 75 | #include "ibuf0ibuf.h" | ||
| 76 | #include "os0event.h" | ||
| 77 | #include "row0mysql.h" | ||
| 78 | #include "sql_backup_lock.h" | ||
| 79 | #include "sql_class.h" | ||
| 80 | #include "sync0sync.h" | ||
| 81 | #include "trx0purge.h" | ||
| 82 | #else /* !UNIV_HOTBACKUP */ | ||
| 83 | #include <cstring> | ||
| 84 | #include "srv0srv.h" | ||
| 85 | #endif /* !UNIV_HOTBACKUP */ | ||
| 86 | #include "system_key.h" | ||
| 87 | |||
| 88 | #include "os0thread-create.h" | ||
| 89 | |||
| 90 | #include "current_thd.h" | ||
| 91 | #include "ha_prototypes.h" | ||
| 92 | |||
| 93 | #include <array> | ||
| 94 | #include <fstream> | ||
| 95 | #include <functional> | ||
| 96 | #include <list> | ||
| 97 | #include <mutex> | ||
| 98 | #include <thread> | ||
| 99 | #include <tuple> | ||
| 100 | #include <unordered_map> | ||
| 101 | |||
| 102 | using Dirs = std::vector<std::string>; | ||
| 103 | using Space_id_set = std::set<space_id_t>; | ||
| 104 | |||
| 105 | constexpr char Fil_path::DB_SEPARATOR; | ||
| 106 | constexpr char Fil_path::OS_SEPARATOR; | ||
| 107 | constexpr const char *Fil_path::SEPARATOR; | ||
| 108 | constexpr const char *Fil_path::DOT_SLASH; | ||
| 109 | constexpr const char *Fil_path::DOT_DOT_SLASH; | ||
| 110 | constexpr const char *Fil_path::SLASH_DOT_DOT_SLASH; | ||
| 111 | |||
| 112 | dberr_t dict_stats_rename_table(const char *old_name, const char *new_name, | ||
| 113 | char *errstr, size_t errstr_sz); | ||
| 114 | |||
| 115 | /** Used for collecting the data in boot_tablespaces() */ | ||
| 116 | namespace dd_fil { | ||
| 117 | |||
| 118 | enum { | ||
| 119 | /** DD Object ID */ | ||
| 120 | OBJECT_ID, | ||
| 121 | |||
| 122 | /** InnoDB tablspace ID */ | ||
| 123 | SPACE_ID, | ||
| 124 | |||
| 125 | /** DD/InnoDB tablespace name */ | ||
| 126 | SPACE_NAME, | ||
| 127 | |||
| 128 | /** Path in DD tablespace */ | ||
| 129 | OLD_PATH, | ||
| 130 | |||
| 131 | /** Path where it was found during the scan. */ | ||
| 132 | NEW_PATH | ||
| 133 | }; | ||
| 134 | |||
| 135 | using Moved = std::tuple<dd::Object_id, space_id_t, std::string, std::string, | ||
| 136 | std::string>; | ||
| 137 | |||
| 138 | using Tablespaces = std::vector<Moved>; | ||
| 139 | } // namespace dd_fil | ||
| 140 | |||
| 141 | 19024 | size_t fil_get_scan_threads(size_t num_files) { | |
| 142 | /* Number of additional threads required to scan all the files. | ||
| 143 | n_threads == 0 means that the main thread itself will do all the | ||
| 144 | work instead of spawning any additional threads. */ | ||
| 145 | 19024 | size_t n_threads = num_files / FIL_SCAN_MAX_TABLESPACES_PER_THREAD; | |
| 146 | |||
| 147 | /* Return if no additional threads are needed. */ | ||
| 148 |
1/2✓ Branch 0 taken 19024 times.
✗ Branch 1 not taken.
|
19024 | if (n_threads == 0) { |
| 149 | 19024 | return 0; | |
| 150 | } | ||
| 151 | |||
| 152 | /* Number of concurrent threads supported by the host machine. */ | ||
| 153 | size_t max_threads = | ||
| 154 | ✗ | FIL_SCAN_THREADS_PER_CORE * std::thread::hardware_concurrency(); | |
| 155 | |||
| 156 | /* If the number of concurrent threads supported by the host | ||
| 157 | machine could not be calculated, assume the supported threads | ||
| 158 | to be FIL_SCAN_MAX_THREADS. */ | ||
| 159 | ✗ | max_threads = max_threads == 0 ? FIL_SCAN_MAX_THREADS : max_threads; | |
| 160 | |||
| 161 | /* Restrict the number of threads to the lower of number of threads | ||
| 162 | supported by the host machine or FIL_SCAN_MAX_THREADS. */ | ||
| 163 | ✗ | if (n_threads > max_threads) { | |
| 164 | ✗ | n_threads = max_threads; | |
| 165 | } | ||
| 166 | |||
| 167 | ✗ | if (n_threads > FIL_SCAN_MAX_THREADS) { | |
| 168 | ✗ | n_threads = FIL_SCAN_MAX_THREADS; | |
| 169 | } | ||
| 170 | |||
| 171 | ✗ | return n_threads; | |
| 172 | } | ||
| 173 | |||
| 174 | /* uint16_t is the index into Tablespace_dirs::m_dirs */ | ||
| 175 | using Scanned_files = std::vector<std::pair<uint16_t, std::string>>; | ||
| 176 | |||
| 177 | #ifdef UNIV_PFS_IO | ||
| 178 | mysql_pfs_key_t innodb_tablespace_open_file_key; | ||
| 179 | #endif /* UNIV_PFS_IO */ | ||
| 180 | |||
| 181 | /** System tablespace. */ | ||
| 182 | fil_space_t *fil_space_t::s_sys_space; | ||
| 183 | |||
| 184 | #ifdef UNIV_HOTBACKUP | ||
| 185 | /** Directories in which remote general tablespaces have been found in the | ||
| 186 | target directory during apply log operation */ | ||
| 187 | Dir_set rem_gen_ts_dirs; | ||
| 188 | |||
| 189 | /** true in case the apply-log operation is being performed | ||
| 190 | in the data directory */ | ||
| 191 | bool replay_in_datadir = false; | ||
| 192 | |||
| 193 | /* Re-define mutex macros to use the Mutex class defined by the MEB | ||
| 194 | source. MEB calls the routines in "fil0fil.cc" in parallel and, | ||
| 195 | therefore, the mutex protecting the critical sections of the tablespace | ||
| 196 | memory cache must be included also in the MEB compilation of this | ||
| 197 | module. */ | ||
| 198 | #undef mutex_create | ||
| 199 | #undef mutex_free | ||
| 200 | #undef mutex_enter | ||
| 201 | #undef mutex_exit | ||
| 202 | #undef mutex_own | ||
| 203 | #undef mutex_validate | ||
| 204 | |||
| 205 | #define mutex_create(I, M) new (M) meb::Mutex() | ||
| 206 | #define mutex_free(M) delete (M) | ||
| 207 | #define mutex_enter(M) (M)->lock() | ||
| 208 | #define mutex_exit(M) (M)->unlock() | ||
| 209 | #define mutex_own(M) 1 | ||
| 210 | #define mutex_validate(M) 1 | ||
| 211 | |||
| 212 | /** Process a MLOG_FILE_CREATE redo record. | ||
| 213 | @param[in] page_id Page id of the redo log record | ||
| 214 | @param[in] flags Tablespace flags | ||
| 215 | @param[in] name Tablespace filename */ | ||
| 216 | static void meb_tablespace_redo_create(const page_id_t &page_id, uint32_t flags, | ||
| 217 | const char *name); | ||
| 218 | |||
| 219 | /** Process a MLOG_FILE_RENAME redo record. | ||
| 220 | @param[in] page_id Page id of the redo log record | ||
| 221 | @param[in] from_name Tablespace from filename | ||
| 222 | @param[in] to_name Tablespace to filename */ | ||
| 223 | static void meb_tablespace_redo_rename(const page_id_t &page_id, | ||
| 224 | const char *from_name, | ||
| 225 | const char *to_name); | ||
| 226 | |||
| 227 | /** Process a MLOG_FILE_DELETE redo record. | ||
| 228 | @param[in] page_id Page id of the redo log record | ||
| 229 | @param[in] name Tablespace filename */ | ||
| 230 | static void meb_tablespace_redo_delete(const page_id_t &page_id, | ||
| 231 | const char *name); | ||
| 232 | |||
| 233 | #endif /* UNIV_HOTBACKUP */ | ||
| 234 | |||
| 235 | /* | ||
| 236 | IMPLEMENTATION OF THE TABLESPACE MEMORY CACHE | ||
| 237 | ============================================= | ||
| 238 | |||
| 239 | The tablespace cache is responsible for providing fast read/write access to | ||
| 240 | tablespaces. File creation and deletion is done in other modules which know | ||
| 241 | more of the logic of the operation, however. | ||
| 242 | |||
| 243 | Only the system tablespace consists of a list of files. The size of these | ||
| 244 | files does not have to be divisible by the database block size, because | ||
| 245 | we may just leave the last incomplete block unused. When a new file is | ||
| 246 | appended to the tablespace, the maximum size of the file is also specified. | ||
| 247 | At the moment, we think that it is best to extend the file to its maximum | ||
| 248 | size already at the creation of the file, because then we can avoid dynamically | ||
| 249 | extending the file when more space is needed for the tablespace. | ||
| 250 | |||
| 251 | Non system tablespaces contain only a single file. | ||
| 252 | |||
| 253 | A block's position in the tablespace is specified with a 32-bit unsigned | ||
| 254 | integer. The files in the list are thought to be catenated, and the block | ||
| 255 | corresponding to an address n is the nth block in the catenated file (where | ||
| 256 | the first block is named the 0th block, and the incomplete block fragments | ||
| 257 | at the end of files are not taken into account). A tablespace can be extended | ||
| 258 | by appending a new file at the end of the list. | ||
| 259 | |||
| 260 | Our tablespace concept is similar to the one of Oracle. | ||
| 261 | |||
| 262 | To have fast access to a tablespace file, we put the data structures to | ||
| 263 | a hash table. Each tablespace file is given an unique 32-bit identifier, | ||
| 264 | its tablespace ID. | ||
| 265 | |||
| 266 | Some operating systems do not support many open files at the same time, or have | ||
| 267 | a limit set for user or process. Therefore, we put the open files that can be | ||
| 268 | easily closed in an LRU-list. If we need to open another file, we may close the | ||
| 269 | file at the end of the LRU-list. When an I/O-operation is pending on a file, the | ||
| 270 | file cannot be closed - we take the file nodes with pending I/O-operations out | ||
| 271 | of the LRU-list and keep a count of pending operations for each such file node. | ||
| 272 | When an operation completes, we decrement the count and return the file to the | ||
| 273 | LRU-list if the count drops to zero. | ||
| 274 | |||
| 275 | The data structure (Fil_shard) that keeps track of the tablespace ID to | ||
| 276 | fil_space_t* mapping are hashed on the tablespace ID. The tablespace name to | ||
| 277 | fil_space_t* mapping is stored in the same shard. A shard tracks the flushing | ||
| 278 | and open state of a file. When we run out open file handles, we use a ticketing | ||
| 279 | system to serialize the file open, see Fil_shard::reserve_open_slot() and | ||
| 280 | Fil_shard::release_open_slot(). | ||
| 281 | |||
| 282 | When updating the global/shared data in Fil_system acquire the mutexes of | ||
| 283 | all shards in ascending order. The shard mutex covers the fil_space_t data | ||
| 284 | members as noted in the fil_space_t and fil_node_t definition. */ | ||
| 285 | |||
| 286 | /** Reference to the server data directory. */ | ||
| 287 | Fil_path MySQL_datadir_path; | ||
| 288 | |||
| 289 | /** Reference to the server undo directory. */ | ||
| 290 | Fil_path MySQL_undo_path; | ||
| 291 | |||
| 292 | /** The undo path is different from any other known directory. */ | ||
| 293 | bool MySQL_undo_path_is_unique; | ||
| 294 | |||
| 295 | /** Common InnoDB file extentions */ | ||
| 296 | const char *dot_ext[] = {"", ".ibd", ".cfg", ".cfp", | ||
| 297 | ".ibt", ".ibu", ".dblwr", ".bdblwr"}; | ||
| 298 | |||
| 299 | /** Number of pending tablespace flushes */ | ||
| 300 | ulint fil_n_pending_tablespace_flushes = 0; | ||
| 301 | |||
| 302 | /** Number of files currently open */ | ||
| 303 | std::atomic_size_t fil_n_files_open{0}; | ||
| 304 | |||
| 305 | /** At this age or older a space/page will be rotated */ | ||
| 306 | extern uint srv_fil_crypt_rotate_key_age; | ||
| 307 | extern ib_mutex_t fil_crypt_threads_mutex; | ||
| 308 | extern ib_mutex_t fil_crypt_list_mutex; | ||
| 309 | |||
| 310 | extern uint srv_n_fil_crypt_threads_requested; | ||
| 311 | |||
| 312 | enum fil_load_status { | ||
| 313 | /** The tablespace file(s) were found and valid. */ | ||
| 314 | FIL_LOAD_OK, | ||
| 315 | |||
| 316 | /** The name no longer matches space_id */ | ||
| 317 | FIL_LOAD_ID_CHANGED, | ||
| 318 | |||
| 319 | /** The file(s) were not found */ | ||
| 320 | FIL_LOAD_NOT_FOUND, | ||
| 321 | |||
| 322 | /** The file(s) were not valid */ | ||
| 323 | FIL_LOAD_INVALID, | ||
| 324 | |||
| 325 | /** The tablespace file ID in the first page doesn't match | ||
| 326 | expected value. */ | ||
| 327 | FIL_LOAD_MISMATCH, | ||
| 328 | |||
| 329 | /** Doublewrite buffer corruption */ | ||
| 330 | FIL_LOAD_DBWLR_CORRUPTION | ||
| 331 | }; | ||
| 332 | |||
| 333 | /** File operations for tablespace */ | ||
| 334 | enum fil_operation_t { | ||
| 335 | |||
| 336 | /** delete a single-table tablespace */ | ||
| 337 | FIL_OPERATION_DELETE, | ||
| 338 | |||
| 339 | /** close a single-table tablespace */ | ||
| 340 | FIL_OPERATION_CLOSE | ||
| 341 | }; | ||
| 342 | |||
| 343 | /** The null file address */ | ||
| 344 | fil_addr_t fil_addr_null = {FIL_NULL, 0}; | ||
| 345 | |||
| 346 | /** Maximum number of pages to read to determine the space ID. */ | ||
| 347 | static const size_t MAX_PAGES_TO_READ = 1; | ||
| 348 | |||
| 349 | #ifndef UNIV_HOTBACKUP | ||
| 350 | /** Maximum number of shards supported. */ | ||
| 351 | static const size_t MAX_SHARDS = 68; | ||
| 352 | |||
| 353 | /** Number of undo shards to reserve. */ | ||
| 354 | static const size_t UNDO_SHARDS = 4; | ||
| 355 | |||
| 356 | /** The UNDO logs have their own shards (4). */ | ||
| 357 | static const size_t UNDO_SHARDS_START = MAX_SHARDS - UNDO_SHARDS; | ||
| 358 | #else /* !UNIV_HOTBACKUP */ | ||
| 359 | |||
| 360 | /** Maximum number of shards supported. */ | ||
| 361 | static const size_t MAX_SHARDS = 1; | ||
| 362 | |||
| 363 | /** The UNDO logs have their own shards (4). */ | ||
| 364 | static const size_t UNDO_SHARDS_START = 0; | ||
| 365 | #endif /* !UNIV_HOTBACKUP */ | ||
| 366 | |||
| 367 | /** We want to store the line number from where it was called. */ | ||
| 368 | #define mutex_acquire() acquire(__LINE__) | ||
| 369 | |||
| 370 | /** Hash a NUL terminated 'string' */ | ||
| 371 | struct Char_Ptr_Hash { | ||
| 372 | /** Hashing function | ||
| 373 | @param[in] ptr NUL terminated string to hash | ||
| 374 | @return the hash */ | ||
| 375 | 11415766 | size_t operator()(const char *ptr) const { | |
| 376 | 11415766 | return static_cast<size_t>(ut::hash_string(ptr)); | |
| 377 | } | ||
| 378 | }; | ||
| 379 | |||
| 380 | /** Compare two 'strings' */ | ||
| 381 | struct Char_Ptr_Compare { | ||
| 382 | /** Compare two NUL terminated strings | ||
| 383 | @param[in] lhs Left hand side | ||
| 384 | @param[in] rhs Right hand side | ||
| 385 | @return true if the contents match */ | ||
| 386 | 835167 | bool operator()(const char *lhs, const char *rhs) const { | |
| 387 | 835167 | return (strcmp(lhs, rhs) == 0); | |
| 388 | } | ||
| 389 | }; | ||
| 390 | |||
| 391 | /** Tablespace files discovered during startup. */ | ||
| 392 | class Tablespace_files { | ||
| 393 | public: | ||
| 394 | using Names = std::vector<std::string, ut::allocator<std::string>>; | ||
| 395 | using Paths = std::unordered_map<space_id_t, Names>; | ||
| 396 | using Undo_num2id = std::unordered_map<space_id_t, space_id_t>; | ||
| 397 | |||
| 398 | /** Default constructor | ||
| 399 | @param[in] dir Directory that the files are under */ | ||
| 400 | explicit Tablespace_files(const std::string &dir); | ||
| 401 | |||
| 402 | /** Add a space ID to filename mapping. | ||
| 403 | @param[in] space_id Tablespace ID | ||
| 404 | @param[in] name File name. | ||
| 405 | @return number of files that map to the space ID */ | ||
| 406 | [[nodiscard]] size_t add(space_id_t space_id, const std::string &name); | ||
| 407 | |||
| 408 | /** Get the file names that map to a space ID | ||
| 409 | @param[in] space_id Tablespace ID | ||
| 410 | @return the filenames that map to space id */ | ||
| 411 | 18873932 | [[nodiscard]] Names *find_by_id(space_id_t space_id) { | |
| 412 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18873932 times.
|
18873932 | ut_ad(space_id != TRX_SYS_SPACE); |
| 413 | |||
| 414 |
2/2✓ Branch 0 taken 7637979 times.
✓ Branch 1 taken 11235953 times.
|
18873932 | if (undo::is_reserved(space_id)) { |
| 415 |
1/2✓ Branch 0 taken 7637979 times.
✗ Branch 1 not taken.
|
7637979 | auto it = m_undo_paths.find(space_id); |
| 416 | |||
| 417 |
2/2✓ Branch 0 taken 7442710 times.
✓ Branch 1 taken 195269 times.
|
7637979 | if (it != m_undo_paths.end()) { |
| 418 | 7442710 | return &it->second; | |
| 419 | } | ||
| 420 | |||
| 421 | } else { | ||
| 422 |
1/2✓ Branch 0 taken 11235953 times.
✗ Branch 1 not taken.
|
11235953 | auto it = m_ibd_paths.find(space_id); |
| 423 | |||
| 424 |
2/2✓ Branch 0 taken 10063525 times.
✓ Branch 1 taken 1172428 times.
|
11235953 | if (it != m_ibd_paths.end()) { |
| 425 | 10063525 | return &it->second; | |
| 426 | } | ||
| 427 | } | ||
| 428 | |||
| 429 | 1367697 | return nullptr; | |
| 430 | } | ||
| 431 | |||
| 432 | /** Get the file name that maps to an undo space number | ||
| 433 | @param[in] space_num undo tablespace number | ||
| 434 | @param[out] space_id undo tablespace ID | ||
| 435 | @return the file name that maps to the space number */ | ||
| 436 | 1217825 | [[nodiscard]] Names *find_by_num(space_id_t space_num, space_id_t &space_id) { | |
| 437 |
3/6✓ Branch 0 taken 1217825 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1217825 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1217825 times.
|
1217825 | ut_ad(space_num > 0 && space_num <= FSP_MAX_UNDO_TABLESPACES); |
| 438 |
1/2✓ Branch 0 taken 1217825 times.
✗ Branch 1 not taken.
|
1217825 | auto it_nums = m_undo_nums.find(space_num); |
| 439 |
2/2✓ Branch 0 taken 1198875 times.
✓ Branch 1 taken 18950 times.
|
1217825 | if (it_nums == m_undo_nums.end()) { |
| 440 | 1198875 | return (nullptr); | |
| 441 | } | ||
| 442 | 18950 | space_id = it_nums->second; | |
| 443 | |||
| 444 |
1/2✓ Branch 0 taken 18950 times.
✗ Branch 1 not taken.
|
18950 | auto it = m_undo_paths.find(space_id); |
| 445 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18950 times.
|
18950 | ut_ad(it != m_undo_paths.end()); |
| 446 | |||
| 447 | 18950 | return (&it->second); | |
| 448 | } | ||
| 449 | |||
| 450 | /** Remove the entry for the space ID. | ||
| 451 | @param[in] space_id Tablespace ID mapping to remove | ||
| 452 | @return true if erase successful */ | ||
| 453 | 6 | [[nodiscard]] bool erase_path(space_id_t space_id) { | |
| 454 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | ut_ad(space_id != TRX_SYS_SPACE); |
| 455 | |||
| 456 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (undo::is_reserved(space_id)) { |
| 457 | ✗ | auto n_erased = m_undo_nums.erase(undo::id2num(space_id)); | |
| 458 | ✗ | ut_ad(n_erased == 1); | |
| 459 | |||
| 460 | ✗ | n_erased = m_undo_paths.erase(space_id); | |
| 461 | |||
| 462 | ✗ | return (n_erased == 1); | |
| 463 | } else { | ||
| 464 | 6 | auto n_erased = m_ibd_paths.erase(space_id); | |
| 465 | |||
| 466 | 6 | return (n_erased == 1); | |
| 467 | } | ||
| 468 | } | ||
| 469 | |||
| 470 | /** Clear all the tablespace data. */ | ||
| 471 | 9683 | void clear() { | |
| 472 | 9683 | m_ibd_paths.clear(); | |
| 473 | 9683 | m_undo_paths.clear(); | |
| 474 | 9683 | m_undo_nums.clear(); | |
| 475 | 9683 | } | |
| 476 | |||
| 477 | /** @return m_dir */ | ||
| 478 | 52553 | const Fil_path &root() const { return m_dir; } | |
| 479 | |||
| 480 | /** @return the directory path specified by the user. */ | ||
| 481 | 17623659 | const std::string &path() const { return m_dir.path(); } | |
| 482 | |||
| 483 | private: | ||
| 484 | /* Note: The file names in m_ibd_paths and m_undo_paths are relative | ||
| 485 | to m_real_path. */ | ||
| 486 | |||
| 487 | /** Mapping from tablespace ID to data filenames */ | ||
| 488 | Paths m_ibd_paths; | ||
| 489 | |||
| 490 | /** Mapping from tablespace ID to Undo files */ | ||
| 491 | Paths m_undo_paths; | ||
| 492 | |||
| 493 | /** Mapping from undo space number to space ID */ | ||
| 494 | Undo_num2id m_undo_nums; | ||
| 495 | |||
| 496 | /** Top level directory where the above files were found. */ | ||
| 497 | Fil_path m_dir; | ||
| 498 | }; | ||
| 499 | |||
| 500 | /** Directories scanned during startup and the files discovered. */ | ||
| 501 | class Tablespace_dirs { | ||
| 502 | public: | ||
| 503 | using Result = std::pair<std::string, Tablespace_files::Names *>; | ||
| 504 | |||
| 505 | /** Constructor */ | ||
| 506 | 9805 | Tablespace_dirs() : m_dirs(), m_checked() {} | |
| 507 | |||
| 508 | /** Normalize and save a directory to scan for IBD and IBU datafiles | ||
| 509 | before recovery. | ||
| 510 | @param[in] directory directory to scan for ibd and ibu files | ||
| 511 | @param[in] is_undo_dir true for an undo directory */ | ||
| 512 | void set_scan_dir(const std::string &directory, bool is_undo_dir = false); | ||
| 513 | |||
| 514 | /** Normalize and save a list of directories to scan for IBD and IBU | ||
| 515 | datafiles before recovery. | ||
| 516 | @param[in] directories Directories to scan for ibd and ibu files */ | ||
| 517 | void set_scan_dirs(const std::string &directories); | ||
| 518 | |||
| 519 | /** Discover tablespaces by reading the header from .ibd files. | ||
| 520 | @return DB_SUCCESS if all goes well */ | ||
| 521 | [[nodiscard]] dberr_t scan(); | ||
| 522 | |||
| 523 | /** Clear all the tablespace file data but leave the list of | ||
| 524 | scanned directories in place. */ | ||
| 525 | 9493 | void clear() { | |
| 526 |
2/2✓ Branch 0 taken 9683 times.
✓ Branch 1 taken 9493 times.
|
19176 | for (auto &dir : m_dirs) { |
| 527 | 9683 | dir.clear(); | |
| 528 | } | ||
| 529 | |||
| 530 | 9493 | m_checked = 0; | |
| 531 | 9493 | } | |
| 532 | |||
| 533 | /** Erase a space ID to filename mapping. | ||
| 534 | @param[in] space_id Tablespace ID to erase | ||
| 535 | @return true if successful */ | ||
| 536 | 6 | [[nodiscard]] bool erase_path(space_id_t space_id) { | |
| 537 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | for (auto &dir : m_dirs) { |
| 538 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | if (dir.erase_path(space_id)) { |
| 539 | 6 | return true; | |
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 543 | ✗ | return false; | |
| 544 | } | ||
| 545 | |||
| 546 | /* Find the first matching space ID -> name mapping. | ||
| 547 | @param[in] space_id Tablespace ID | ||
| 548 | @return directory searched and pointer to names that map to the | ||
| 549 | tablespace ID */ | ||
| 550 | 18918891 | [[nodiscard]] Result find_by_id(space_id_t space_id) { | |
| 551 |
2/2✓ Branch 0 taken 18873931 times.
✓ Branch 1 taken 1412657 times.
|
20286588 | for (auto &dir : m_dirs) { |
| 552 |
1/2✓ Branch 0 taken 18873931 times.
✗ Branch 1 not taken.
|
18873931 | const auto names = dir.find_by_id(space_id); |
| 553 | |||
| 554 |
2/2✓ Branch 0 taken 17506234 times.
✓ Branch 1 taken 1367697 times.
|
18873931 | if (names != nullptr) { |
| 555 |
1/2✓ Branch 0 taken 17506234 times.
✗ Branch 1 not taken.
|
17506234 | return (Result{dir.path(), names}); |
| 556 | } | ||
| 557 | } | ||
| 558 | |||
| 559 |
1/2✓ Branch 0 taken 1412657 times.
✗ Branch 1 not taken.
|
1412657 | return (Result{"", nullptr}); |
| 560 | } | ||
| 561 | |||
| 562 | /* Find the matching space number ->space ID -> name mapping. | ||
| 563 | @param[in] space_num undo tablespace number | ||
| 564 | @param[out] space_id undo tablespace ID | ||
| 565 | @return directory searched and pointer to name that maps to the | ||
| 566 | tablespace number */ | ||
| 567 | 1196733 | [[nodiscard]] Result find_by_num(space_id_t space_num, space_id_t &space_id) { | |
| 568 |
2/2✓ Branch 0 taken 1217825 times.
✓ Branch 1 taken 1177783 times.
|
2395608 | for (auto &dir : m_dirs) { |
| 569 |
1/2✓ Branch 0 taken 1217825 times.
✗ Branch 1 not taken.
|
1217825 | const auto names = dir.find_by_num(space_num, space_id); |
| 570 | |||
| 571 |
2/2✓ Branch 0 taken 18950 times.
✓ Branch 1 taken 1198875 times.
|
1217825 | if (names != nullptr) { |
| 572 |
1/2✓ Branch 0 taken 18950 times.
✗ Branch 1 not taken.
|
18950 | return Result{dir.path(), names}; |
| 573 | } | ||
| 574 | } | ||
| 575 | |||
| 576 |
1/2✓ Branch 0 taken 1177783 times.
✗ Branch 1 not taken.
|
1177783 | return Result{"", nullptr}; |
| 577 | } | ||
| 578 | |||
| 579 | /** Determine if this Fil_path contains the path provided. | ||
| 580 | @param[in] path file or directory path to compare. | ||
| 581 | @return true if this Fil_path contains path */ | ||
| 582 | 15110 | [[nodiscard]] bool contains(const std::string &path) const { | |
| 583 |
1/2✓ Branch 0 taken 15110 times.
✗ Branch 1 not taken.
|
15110 | const Fil_path descendant{path}; |
| 584 | |||
| 585 |
2/2✓ Branch 0 taken 15911 times.
✓ Branch 1 taken 116 times.
|
16027 | for (const auto &dir : m_dirs) { |
| 586 |
5/6✓ Branch 0 taken 15911 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6239 times.
✓ Branch 3 taken 9672 times.
✓ Branch 4 taken 14994 times.
✓ Branch 5 taken 917 times.
|
22150 | if (dir.root().is_same_as(descendant) || |
| 587 |
3/4✓ Branch 0 taken 6239 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5322 times.
✓ Branch 3 taken 917 times.
|
6239 | dir.root().is_ancestor(descendant)) { |
| 588 | 14994 | return true; | |
| 589 | } | ||
| 590 | } | ||
| 591 | 116 | return false; | |
| 592 | 15110 | } | |
| 593 | |||
| 594 | /** Get the list of directories that InnoDB knows about. | ||
| 595 | @return the list of directories 'dir1;dir2;....;dirN' */ | ||
| 596 | 9693 | std::string get_dirs() const { | |
| 597 | 9693 | std::string dirs; | |
| 598 | |||
| 599 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9693 times.
|
9693 | ut_ad(!m_dirs.empty()); |
| 600 | |||
| 601 |
2/2✓ Branch 0 taken 9887 times.
✓ Branch 1 taken 9693 times.
|
19580 | for (const auto &dir : m_dirs) { |
| 602 |
1/2✓ Branch 0 taken 9887 times.
✗ Branch 1 not taken.
|
9887 | dirs.append(dir.root()); |
| 603 |
1/2✓ Branch 0 taken 9887 times.
✗ Branch 1 not taken.
|
9887 | dirs.push_back(FIL_PATH_SEPARATOR); |
| 604 | } | ||
| 605 | |||
| 606 | 9693 | dirs.pop_back(); | |
| 607 | |||
| 608 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9693 times.
|
9693 | ut_ad(!dirs.empty()); |
| 609 | |||
| 610 | 9693 | return dirs; | |
| 611 | } | ||
| 612 | |||
| 613 | private: | ||
| 614 | /** Print the duplicate filenames for a tablespace ID to the log | ||
| 615 | @param[in] duplicates Duplicate tablespace IDs*/ | ||
| 616 | void print_duplicates(const Space_id_set &duplicates); | ||
| 617 | |||
| 618 | /** first=dir path from the user, second=files found under first. */ | ||
| 619 | using Scanned = std::vector<Tablespace_files>; | ||
| 620 | |||
| 621 | /** Report a warning that a path is being ignored and include the reason. */ | ||
| 622 | void warn_ignore(std::string path_in, const char *reason); | ||
| 623 | |||
| 624 | /** Add a single path specification to this list of tablespace directories. | ||
| 625 | Convert it to an absolute path. Check if the path is valid. Ignore | ||
| 626 | unreadable, duplicate or invalid directories. | ||
| 627 | @param[in] str Path specification to tokenize | ||
| 628 | @param[in] is_undo_dir true for an undo directory */ | ||
| 629 | void add_path(const std::string &str, bool is_undo_dir = false); | ||
| 630 | |||
| 631 | /** Add a delimited list of path specifications to this list of tablespace | ||
| 632 | directories. Convert relative paths to absolute paths. Check if the paths | ||
| 633 | are valid. Ignore unreadable, duplicate or invalid directories. | ||
| 634 | @param[in] str Path specification to tokenize | ||
| 635 | @param[in] delimiters Delimiters */ | ||
| 636 | void add_paths(const std::string &str, const std::string &delimiters); | ||
| 637 | |||
| 638 | using Const_iter = Scanned_files::const_iterator; | ||
| 639 | |||
| 640 | /** Check for duplicate tablespace IDs. | ||
| 641 | @param[in] start Start of slice | ||
| 642 | @param[in] end End of slice | ||
| 643 | @param[in] thread_id Thread ID | ||
| 644 | @param[in,out] mutex Mutex protecting the global state | ||
| 645 | @param[in,out] unique To check for duplicates | ||
| 646 | @param[in,out] duplicates Duplicate space IDs found */ | ||
| 647 | void duplicate_check(const Const_iter &start, const Const_iter &end, | ||
| 648 | size_t thread_id, std::mutex *mutex, | ||
| 649 | Space_id_set *unique, Space_id_set *duplicates); | ||
| 650 | |||
| 651 | private: | ||
| 652 | /** Directories scanned and the files discovered under them. */ | ||
| 653 | Scanned m_dirs; | ||
| 654 | |||
| 655 | /** Number of files checked. */ | ||
| 656 | std::atomic_size_t m_checked; | ||
| 657 | }; | ||
| 658 | |||
| 659 | /** Determine if space flushing should be disabled, for example when user has | ||
| 660 | explicitly disabled fsync(). */ | ||
| 661 | 27910652 | static inline bool fil_disable_space_flushing(const fil_space_t *space) { | |
| 662 | #ifndef _WIN32 | ||
| 663 |
2/2✓ Branch 0 taken 26032925 times.
✓ Branch 1 taken 1877727 times.
|
27910652 | if (space->purpose == FIL_TYPE_TABLESPACE && |
| 664 |
2/2✓ Branch 0 taken 99 times.
✓ Branch 1 taken 26032826 times.
|
26032925 | srv_unix_file_flush_method == SRV_UNIX_O_DIRECT_NO_FSYNC) { |
| 665 | 99 | return true; | |
| 666 | } | ||
| 667 | #endif /* !_WIN32 */ | ||
| 668 |
2/2✓ Branch 0 taken 1874890 times.
✓ Branch 1 taken 26035663 times.
|
27910553 | if (space->purpose == FIL_TYPE_TEMPORARY) { |
| 669 | 1874890 | return true; | |
| 670 | } | ||
| 671 | 26035663 | return false; | |
| 672 | } | ||
| 673 | |||
| 674 | class Fil_shard { | ||
| 675 | using File_list = UT_LIST_BASE_NODE_T(fil_node_t, LRU); | ||
| 676 | using Space_list = UT_LIST_BASE_NODE_T(fil_space_t, unflushed_spaces); | ||
| 677 | using Full_space_list = UT_LIST_BASE_NODE_T(fil_space_t, space_list); | ||
| 678 | using Rotation_list = UT_LIST_BASE_NODE_T(fil_space_t, rotation_list); | ||
| 679 | using Spaces = std::unordered_map<space_id_t, fil_space_t *>; | ||
| 680 | |||
| 681 | using Names = std::unordered_map<const char *, fil_space_t *, Char_Ptr_Hash, | ||
| 682 | Char_Ptr_Compare>; | ||
| 683 | |||
| 684 | public: | ||
| 685 | /** Constructor | ||
| 686 | @param[in] shard_id Shard ID */ | ||
| 687 | explicit Fil_shard(size_t shard_id); | ||
| 688 | |||
| 689 | /** Destructor */ | ||
| 690 | 569772 | ~Fil_shard() { | |
| 691 | 569772 | mutex_destroy(&m_mutex); | |
| 692 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 569772 times.
|
569772 | ut_a(UT_LIST_GET_LEN(m_LRU) == 0); |
| 693 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 569772 times.
|
569772 | ut_a(UT_LIST_GET_LEN(m_unflushed_spaces) == 0); |
| 694 | 569772 | } | |
| 695 | |||
| 696 | /** @return the shard ID */ | ||
| 697 | size_t id() const { return m_id; } | ||
| 698 | |||
| 699 | /** Acquire the mutex. | ||
| 700 | @param[in] line Line number from where it was called */ | ||
| 701 | 2663997833 | void acquire(int line) const { | |
| 702 | #ifndef UNIV_HOTBACKUP | ||
| 703 | 2663997833 | m_mutex.enter(srv_n_spin_wait_rounds, srv_spin_wait_delay, __FILE__, line); | |
| 704 | #else | ||
| 705 | mutex_enter(&m_mutex); | ||
| 706 | #endif /* !UNIV_HOTBACKUP */ | ||
| 707 | 2663512221 | } | |
| 708 | |||
| 709 | /** Release the mutex. */ | ||
| 710 | 2664196358 | void mutex_release() const { mutex_exit(&m_mutex); } | |
| 711 | |||
| 712 | #ifdef UNIV_DEBUG | ||
| 713 | /** @return true if the mutex is owned. */ | ||
| 714 | 3866671437 | bool mutex_owned() const { return mutex_own(&m_mutex); } | |
| 715 | #endif /* UNIV_DEBUG */ | ||
| 716 | |||
| 717 | /** Acquire a tablespace to prevent it from being dropped concurrently. | ||
| 718 | The thread must call Fil_shard::fil_space_release() when the operation | ||
| 719 | is done. | ||
| 720 | @param[in] space tablespace to acquire | ||
| 721 | @return true if not space->stop_new_ops */ | ||
| 722 | bool space_acquire(fil_space_t *space); | ||
| 723 | |||
| 724 | /** Release a tablespace acquired with Fil_shard::space_acquire(). | ||
| 725 | @param[in,out] space tablespace to release */ | ||
| 726 | void space_release(fil_space_t *space); | ||
| 727 | |||
| 728 | /** Fetch the fil_space_t instance that maps to space_id. Does not look | ||
| 729 | through system reserved spaces. | ||
| 730 | @param[in] space_id Tablespace ID to lookup | ||
| 731 | @return tablespace instance or nullptr if not found. */ | ||
| 732 | 1391921647 | [[nodiscard]] fil_space_t *get_space_by_id_from_map( | |
| 733 | space_id_t space_id) const { | ||
| 734 |
2/4✓ Branch 0 taken 1391926032 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1391924125 times.
|
1391921647 | ut_ad(mutex_owned()); |
| 735 | |||
| 736 |
1/2✓ Branch 0 taken 1391928007 times.
✗ Branch 1 not taken.
|
1391924125 | auto it = m_spaces.find(space_id); |
| 737 | |||
| 738 | /* The system tablespace must always be found */ | ||
| 739 |
4/8✓ Branch 0 taken 891489 times.
✓ Branch 1 taken 1391027284 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 891489 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1391918582 times.
|
1391928007 | ut_ad(it != m_spaces.end() || space_id != 0 || srv_is_being_started); |
| 740 | |||
| 741 |
2/2✓ Branch 0 taken 891489 times.
✓ Branch 1 taken 1391024281 times.
|
1391918582 | if (it == m_spaces.end()) { |
| 742 | 891489 | return nullptr; | |
| 743 | } | ||
| 744 | |||
| 745 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1391023897 times.
|
1391024281 | ut_ad(it->second->magic_n == FIL_SPACE_MAGIC_N); |
| 746 |
5/8✓ Branch 0 taken 1391023096 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1246281820 times.
✓ Branch 3 taken 144741276 times.
✓ Branch 4 taken 1246279899 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1391021357 times.
|
1391023897 | ut_ad(fsp_is_system_temporary(space_id) || it->second->files.size() == 1); |
| 747 | |||
| 748 | 1391021357 | return it->second; | |
| 749 | } | ||
| 750 | |||
| 751 | /** Fetch the fil_space_t instance that maps to space_id. | ||
| 752 | @param[in] space_id Tablespace ID to lookup | ||
| 753 | @return tablespace instance or nullptr if not found. */ | ||
| 754 | fil_space_t *get_space_by_id(space_id_t space_id) const; | ||
| 755 | |||
| 756 | /** Fetch the fil_space_t instance that maps to the name. | ||
| 757 | @param[in] name Tablespace name to lookup | ||
| 758 | @return tablespace instance or nullptr if not found. */ | ||
| 759 | 10312733 | [[nodiscard]] fil_space_t *get_space_by_name(const char *name) const { | |
| 760 |
2/4✓ Branch 0 taken 10312733 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10312733 times.
|
10312733 | ut_ad(mutex_owned()); |
| 761 | |||
| 762 |
1/2✓ Branch 0 taken 10312733 times.
✗ Branch 1 not taken.
|
10312733 | auto it = m_names.find(name); |
| 763 | |||
| 764 |
2/2✓ Branch 0 taken 9919750 times.
✓ Branch 1 taken 392983 times.
|
10312733 | if (it == m_names.end()) { |
| 765 | 9919750 | return nullptr; | |
| 766 | } | ||
| 767 | |||
| 768 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 392983 times.
|
392983 | ut_ad(it->second->magic_n == FIL_SPACE_MAGIC_N); |
| 769 | |||
| 770 | 392983 | return it->second; | |
| 771 | } | ||
| 772 | |||
| 773 | /** Tries to close a file in the shard LRU list. | ||
| 774 | The caller must hold the Fil_shard::m_mutex. | ||
| 775 | @return true if success, false if should retry later */ | ||
| 776 | [[nodiscard]] bool close_files_in_LRU(); | ||
| 777 | |||
| 778 | /** Remove the file node from the LRU list. | ||
| 779 | @param[in,out] file File for the tablespace */ | ||
| 780 | void remove_from_LRU(fil_node_t *file); | ||
| 781 | |||
| 782 | /** Add the file node to the LRU list if required. | ||
| 783 | @param[in,out] file File for the tablespace */ | ||
| 784 | void add_to_lru_if_needed(fil_node_t *file); | ||
| 785 | |||
| 786 | /** Open all the system files. | ||
| 787 | @param[in] max_n_open Maximum number of open files allowed | ||
| 788 | @param[in,out] n_open Current number of open files */ | ||
| 789 | void open_system_tablespaces(size_t max_n_open, size_t *n_open); | ||
| 790 | |||
| 791 | /** Close a tablespace file. | ||
| 792 | @param[in,out] file Tablespace file to close */ | ||
| 793 | void close_file(fil_node_t *file); | ||
| 794 | |||
| 795 | /** Close a tablespace file based on tablespace ID. | ||
| 796 | @param[in] space_id Tablespace ID | ||
| 797 | @return false if space_id was not found. */ | ||
| 798 | bool close_file(space_id_t space_id); | ||
| 799 | |||
| 800 | /** Prepare to free a file object from a tablespace | ||
| 801 | memory cache. | ||
| 802 | @param[in,out] file Tablespace file | ||
| 803 | @param[in] space tablespace */ | ||
| 804 | void file_close_to_free(fil_node_t *file, fil_space_t *space); | ||
| 805 | |||
| 806 | /** Close all open files. */ | ||
| 807 | void close_all_files(); | ||
| 808 | |||
| 809 | #ifndef UNIV_HOTBACKUP | ||
| 810 | #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG | ||
| 811 | /** Check that each fil_space_t::m_n_ref_count in this shard matches the | ||
| 812 | number of pages counted in the buffer pool. | ||
| 813 | @param[in] buffer_pool_references Map of spaces instances to the count | ||
| 814 | of their pages in the buffer pool. */ | ||
| 815 | void validate_space_reference_count(Space_References &buffer_pool_references); | ||
| 816 | #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ | ||
| 817 | #endif /* !UNIV_HOTBACKUP */ | ||
| 818 | |||
| 819 | /** Determine if the tablespace needs encryption rotation. | ||
| 820 | @param[in] space tablespace to rotate | ||
| 821 | @return true if the tablespace needs to be rotated, false if not. */ | ||
| 822 | bool needs_encryption_rotate(fil_space_t *space); | ||
| 823 | |||
| 824 | /** Rotate the tablespace keys by new master key. | ||
| 825 | @param[in,out] rotate_count A cumulative count of all tablespaces rotated | ||
| 826 | in the Fil_system. | ||
| 827 | @return the number of tablespaces that failed to rotate. */ | ||
| 828 | [[nodiscard]] size_t encryption_rotate(size_t *rotate_count); | ||
| 829 | |||
| 830 | /** Detach a space object from the tablespace memory cache and | ||
| 831 | closes the tablespace files but does not delete them. | ||
| 832 | There must not be any pending I/O's or flushes on the files. | ||
| 833 | @param[in,out] space tablespace */ | ||
| 834 | void space_detach(fil_space_t *space); | ||
| 835 | |||
| 836 | /** Remove the fil_space_t instance from the maps used to search for it. | ||
| 837 | @param[in] space_id Tablespace ID to remove from maps. */ | ||
| 838 | 187505 | void space_remove_from_lookup_maps(space_id_t space_id) { | |
| 839 |
2/4✓ Branch 0 taken 187505 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 187505 times.
|
187505 | ut_ad(mutex_owned()); |
| 840 | |||
| 841 |
1/2✓ Branch 0 taken 187505 times.
✗ Branch 1 not taken.
|
187505 | auto it = m_spaces.find(space_id); |
| 842 | |||
| 843 |
1/2✓ Branch 0 taken 187505 times.
✗ Branch 1 not taken.
|
187505 | if (it != m_spaces.end()) { |
| 844 |
1/2✓ Branch 0 taken 187505 times.
✗ Branch 1 not taken.
|
187505 | m_names.erase(it->second->name); |
| 845 |
1/2✓ Branch 0 taken 187504 times.
✗ Branch 1 not taken.
|
187505 | m_spaces.erase(it); |
| 846 | } | ||
| 847 | 187504 | } | |
| 848 | |||
| 849 | #ifndef UNIV_HOTBACKUP | ||
| 850 | /** Move the space to the deleted list and remove from the default | ||
| 851 | lookup set. | ||
| 852 | @param[in, out] space Space instance to delete. */ | ||
| 853 | 181 | void space_prepare_for_delete(fil_space_t *space) noexcept { | |
| 854 | 181 | mutex_acquire(); | |
| 855 | |||
| 856 | 181 | space->set_deleted(); | |
| 857 | |||
| 858 | /* Remove access to the fil_space_t instance. */ | ||
| 859 | 181 | space_remove_from_lookup_maps(space->id); | |
| 860 | |||
| 861 | 181 | m_deleted_spaces.push_back({space->id, space}); | |
| 862 | |||
| 863 | 181 | space_detach(space); | |
| 864 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 181 times.
|
181 | ut_a(space->files.size() == 1); |
| 865 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 181 times.
|
181 | ut_a(space->files.front().n_pending_ios == 0); |
| 866 | |||
| 867 | 181 | mutex_release(); | |
| 868 | 181 | } | |
| 869 | |||
| 870 | /** Purge entries from m_deleted_spaces that are no longer referenced by a | ||
| 871 | buffer pool page. This is no longer required to be done during checkpoint - | ||
| 872 | this is done here for historical reasons - it has to be done periodically | ||
| 873 | somewhere. */ | ||
| 874 | 38088024 | void purge() { | |
| 875 | /* Avoid cleaning up old undo files while this is on. */ | ||
| 876 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38088024 times.
|
38088024 | DBUG_EXECUTE_IF("ib_undo_trunc_checkpoint_off", return;); |
| 877 | |||
| 878 | 38088024 | mutex_acquire(); | |
| 879 |
2/2✓ Branch 0 taken 682587 times.
✓ Branch 1 taken 38088024 times.
|
38770611 | for (auto it = m_deleted_spaces.begin(); it != m_deleted_spaces.end();) { |
| 880 | 682587 | auto space = it->second; | |
| 881 | |||
| 882 |
3/4✓ Branch 0 taken 682587 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 181544 times.
✓ Branch 3 taken 501043 times.
|
682587 | if (space->has_no_references()) { |
| 883 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 181544 times.
|
181544 | ut_a(space->files.size() == 1); |
| 884 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 181544 times.
|
181544 | ut_a(space->files.front().n_pending_ios == 0); |
| 885 | |||
| 886 |
1/2✓ Branch 0 taken 181544 times.
✗ Branch 1 not taken.
|
181544 | space_free_low(space); |
| 887 | |||
| 888 |
1/2✓ Branch 0 taken 181544 times.
✗ Branch 1 not taken.
|
181544 | it = m_deleted_spaces.erase(it); |
| 889 | } else { | ||
| 890 | 501043 | ++it; | |
| 891 | } | ||
| 892 | } | ||
| 893 | |||
| 894 | 38088024 | mutex_release(); | |
| 895 | } | ||
| 896 | |||
| 897 | /** Count how many truncated undo space IDs are still tracked in | ||
| 898 | the buffer pool and the file_system cache. | ||
| 899 | @param[in] undo_num undo tablespace number. | ||
| 900 | @return number of undo tablespaces that are still in memory. */ | ||
| 901 | 3599036 | size_t count_undo_deleted(space_id_t undo_num) noexcept { | |
| 902 | 3599036 | size_t count = 0; | |
| 903 | |||
| 904 | 3599036 | mutex_acquire(); | |
| 905 | |||
| 906 |
2/2✓ Branch 0 taken 167087 times.
✓ Branch 1 taken 3599036 times.
|
3766123 | for (auto deleted : m_deleted_spaces) { |
| 907 |
2/2✓ Branch 0 taken 144 times.
✓ Branch 1 taken 166943 times.
|
167087 | if (undo::id2num(deleted.first) == undo_num) { |
| 908 | 144 | count++; | |
| 909 | } | ||
| 910 | } | ||
| 911 | |||
| 912 | 3599036 | mutex_release(); | |
| 913 | |||
| 914 | 3599036 | return count; | |
| 915 | } | ||
| 916 | |||
| 917 | /** Check if a particular space_id for a page in the buffer pool has | ||
| 918 | been deleted recently. Its space_id will be found in m_deleted_spaces | ||
| 919 | until Fil:shard::checkpoint removes the fil_space_t from Fil_system. | ||
| 920 | @param[in] space_id Tablespace ID to check. | ||
| 921 | @return true if this space_id is in the list of recently deleted spaces. */ | ||
| 922 | ✗ | bool is_deleted(space_id_t space_id) { | |
| 923 | ✗ | bool found = false; | |
| 924 | |||
| 925 | ✗ | mutex_acquire(); | |
| 926 | |||
| 927 | ✗ | for (auto deleted : m_deleted_spaces) { | |
| 928 | ✗ | if (deleted.first == space_id) { | |
| 929 | ✗ | found = true; | |
| 930 | ✗ | break; | |
| 931 | } | ||
| 932 | } | ||
| 933 | |||
| 934 | ✗ | mutex_release(); | |
| 935 | |||
| 936 | ✗ | return found; | |
| 937 | } | ||
| 938 | |||
| 939 | #endif /* !UNIV_HOTBACKUP */ | ||
| 940 | |||
| 941 | /** Frees a space object from the tablespace memory cache. | ||
| 942 | Closes a tablespaces' files but does not delete them. | ||
| 943 | There must not be any pending I/O's or flushes on the files. | ||
| 944 | @param[in] space_id Tablespace ID | ||
| 945 | @return fil_space_t instance on success or nullptr */ | ||
| 946 | [[nodiscard]] fil_space_t *space_free(space_id_t space_id); | ||
| 947 | |||
| 948 | /** Map the space ID and name to the tablespace instance. | ||
| 949 | @param[in] space Tablespace instance */ | ||
| 950 | void space_add(fil_space_t *space, fil_encryption_t mode); | ||
| 951 | |||
| 952 | /** Prepare to free a file. Remove from the unflushed list | ||
| 953 | if there are no pending flushes. | ||
| 954 | @param[in,out] file File instance to free */ | ||
| 955 | void prepare_to_free_file(fil_node_t *file); | ||
| 956 | |||
| 957 | /** If the tablespace is on the unflushed list and there | ||
| 958 | are no pending flushes then remove from the unflushed list. | ||
| 959 | @param[in,out] space Tablespace to remove*/ | ||
| 960 | void remove_from_unflushed_list(fil_space_t *space); | ||
| 961 | |||
| 962 | /** Updates the data structures when an I/O operation | ||
| 963 | finishes. Updates the pending I/O's field in the file | ||
| 964 | appropriately. | ||
| 965 | @param[in] file Tablespace file | ||
| 966 | @param[in] type Marks the file as modified type == WRITE */ | ||
| 967 | void complete_io(fil_node_t *file, const IORequest &type); | ||
| 968 | |||
| 969 | /** Prepares a file for I/O. Opens the file if it is closed. Updates the | ||
| 970 | pending I/O's field in the file and the system appropriately. Takes the file | ||
| 971 | off the LRU list if it is in the LRU list. | ||
| 972 | @param[in] file Tablespace file for IO | ||
| 973 | @return false if the file can't be opened, otherwise true */ | ||
| 974 | [[nodiscard]] bool prepare_file_for_io(fil_node_t *file); | ||
| 975 | |||
| 976 | /** Remap the tablespace to the new name. | ||
| 977 | @param[in] space Tablespace instance, with old name. | ||
| 978 | @param[in] new_name New tablespace name */ | ||
| 979 | void update_space_name_map(fil_space_t *space, const char *new_name); | ||
| 980 | |||
| 981 | /** Flush to disk the writes in file spaces possibly cached by the OS | ||
| 982 | (note: spaces of type FIL_TYPE_TEMPORARY are skipped) */ | ||
| 983 | void flush_file_spaces(); | ||
| 984 | |||
| 985 | /** Try to extend a tablespace if it is smaller than the specified size. | ||
| 986 | @param[in,out] space tablespace | ||
| 987 | @param[in] size desired size in pages | ||
| 988 | @return whether the tablespace is at least as big as requested */ | ||
| 989 | [[nodiscard]] bool space_extend(fil_space_t *space, page_no_t size); | ||
| 990 | |||
| 991 | /** Flushes to disk possible writes cached by the OS. If the space does | ||
| 992 | not exist or is being dropped, does not do anything. | ||
| 993 | @param[in] space_id file space ID (id of tablespace of the database) | ||
| 994 | */ | ||
| 995 | void space_flush(space_id_t space_id); | ||
| 996 | |||
| 997 | /** Open a file of a tablespace. | ||
| 998 | The caller must own the shard mutex. | ||
| 999 | @param[in,out] file Tablespace file | ||
| 1000 | @return false if the file can't be opened, otherwise true */ | ||
| 1001 | [[nodiscard]] bool open_file(fil_node_t *file); | ||
| 1002 | |||
| 1003 | /** Checks if all the file nodes in a space are flushed. The caller must hold | ||
| 1004 | the fil_system mutex. | ||
| 1005 | @param[in] space Tablespace to check | ||
| 1006 | @return true if all are flushed */ | ||
| 1007 | [[nodiscard]] bool space_is_flushed(const fil_space_t *space); | ||
| 1008 | |||
| 1009 | /** Open each file of a tablespace if not already open. | ||
| 1010 | @param[in] space_id tablespace identifier | ||
| 1011 | @retval true if all file nodes were opened | ||
| 1012 | @retval false on failure */ | ||
| 1013 | [[nodiscard]] bool space_open(space_id_t space_id); | ||
| 1014 | |||
| 1015 | /** Opens the files associated with a tablespace and returns a | ||
| 1016 | pointer to the fil_space_t that is in the memory cache associated | ||
| 1017 | with a space id. | ||
| 1018 | @param[in] space_id Get the tablespace instance or this ID | ||
| 1019 | @return file_space_t pointer, nullptr if space not found */ | ||
| 1020 | [[nodiscard]] fil_space_t *space_load(space_id_t space_id); | ||
| 1021 | |||
| 1022 | /** Wait for pending operations on a tablespace to stop. | ||
| 1023 | @param[in] space_id Tablespace ID | ||
| 1024 | @param[out] space tablespace instance in memory | ||
| 1025 | @param[out] path tablespace path | ||
| 1026 | @return DB_SUCCESS or DB_TABLESPACE_NOT_FOUND. */ | ||
| 1027 | [[nodiscard]] dberr_t wait_for_pending_operations(space_id_t space_id, | ||
| 1028 | fil_space_t *&space, | ||
| 1029 | char **path) const; | ||
| 1030 | |||
| 1031 | /** Rename a single-table tablespace. | ||
| 1032 | The tablespace must exist in the memory cache. | ||
| 1033 | @param[in] space_id Tablespace ID | ||
| 1034 | @param[in] old_path Old file name | ||
| 1035 | @param[in] new_name New tablespace name in the schema/space | ||
| 1036 | @param[in] new_path_in New file name, or nullptr if it | ||
| 1037 | is located in the normal data directory | ||
| 1038 | @return InnoDB error code */ | ||
| 1039 | [[nodiscard]] dberr_t space_rename(space_id_t space_id, const char *old_path, | ||
| 1040 | const char *new_name, | ||
| 1041 | const char *new_path_in); | ||
| 1042 | |||
| 1043 | /** Deletes an IBD or IBU tablespace. | ||
| 1044 | The tablespace must be cached in the memory cache. This will delete the | ||
| 1045 | datafile, fil_space_t & fil_node_t entries from the file_system_t cache. | ||
| 1046 | @param[in] space_id Tablespace ID | ||
| 1047 | @param[in] buf_remove Specify the action to take on the pages | ||
| 1048 | for this table in the buffer pool. | ||
| 1049 | @return DB_SUCCESS, DB_TABLESPCE_NOT_FOUND or DB_IO_ERROR */ | ||
| 1050 | [[nodiscard]] dberr_t space_delete(space_id_t space_id, | ||
| 1051 | buf_remove_t buf_remove); | ||
| 1052 | |||
| 1053 | /** Truncate the tablespace to needed size. | ||
| 1054 | @param[in] space_id Tablespace ID to truncate | ||
| 1055 | @param[in] size_in_pages Truncate size. | ||
| 1056 | @return true if truncate was successful. */ | ||
| 1057 | [[nodiscard]] bool space_truncate(space_id_t space_id, | ||
| 1058 | page_no_t size_in_pages); | ||
| 1059 | |||
| 1060 | /** Create a space memory object and put it to the fil_system hash table. | ||
| 1061 | The tablespace name is independent from the tablespace file-name. | ||
| 1062 | Error messages are issued to the server log. | ||
| 1063 | @param[in] name Tablespace name | ||
| 1064 | @param[in] space_id Tablespace identifier | ||
| 1065 | @param[in] flags Tablespace flags | ||
| 1066 | @param[in] purpose Tablespace purpose | ||
| 1067 | @return pointer to created tablespace, to be filled in with fil_node_create() | ||
| 1068 | @retval nullptr on failure (such as when the same tablespace exists) */ | ||
| 1069 | [[nodiscard]] fil_space_t *space_create( | ||
| 1070 | const char *name, space_id_t space_id, uint32_t flags, fil_type_t purpose, | ||
| 1071 | fil_space_crypt_t *crypt_data, | ||
| 1072 | fil_encryption_t mode = FIL_ENCRYPTION_DEFAULT); | ||
| 1073 | |||
| 1074 | /** Adjust temporary auto-generated names created during | ||
| 1075 | file discovery with correct tablespace names from the DD. | ||
| 1076 | @param[in,out] space Tablespace | ||
| 1077 | @param[in] dd_space_name Tablespace name from the DD | ||
| 1078 | @return true if the tablespace is a general or undo tablespace. */ | ||
| 1079 | bool adjust_space_name(fil_space_t *space, const char *dd_space_name); | ||
| 1080 | |||
| 1081 | /** Returns true if a matching tablespace exists in the InnoDB | ||
| 1082 | tablespace memory cache. | ||
| 1083 | @param[in] space_id Tablespace ID | ||
| 1084 | @param[in] name Tablespace name used in fil_space_create(). | ||
| 1085 | @param[in] print_err Print detailed error information to the | ||
| 1086 | error log if a matching tablespace is | ||
| 1087 | not found from memory. | ||
| 1088 | @param[in] adjust_space Whether to adjust space id on mismatch | ||
| 1089 | @return true if a matching tablespace exists in the memory cache */ | ||
| 1090 | [[nodiscard]] bool space_check_exists(space_id_t space_id, const char *name, | ||
| 1091 | bool print_err, bool adjust_space); | ||
| 1092 | |||
| 1093 | /** Read or write data. This operation could be asynchronous (aio). | ||
| 1094 | @param[in] type IO context | ||
| 1095 | @param[in] sync whether synchronous aio is desired | ||
| 1096 | @param[in] page_id page id | ||
| 1097 | @param[in] page_size page size | ||
| 1098 | @param[in] byte_offset remainder of offset in bytes; in AIO this must | ||
| 1099 | be divisible by the OS block size | ||
| 1100 | @param[in] len how many bytes to read or write; this | ||
| 1101 | must not cross a file boundary; in AIO this must be a block size multiple | ||
| 1102 | @param[in,out] buf buffer where to store read data or from | ||
| 1103 | where to write; in AIO this must be appropriately aligned | ||
| 1104 | @param[in] message message for AIO handler if !sync, else ignored | ||
| 1105 | @param[in] should_buffer whether to buffer an aio request. AIO read | ||
| 1106 | ahead uses this. If you plan to use this parameter, make sure you remember to | ||
| 1107 | call os_aio_dispatch_read_array_submit() when you're ready to commit all your | ||
| 1108 | requests. | ||
| 1109 | @return error code | ||
| 1110 | @retval DB_SUCCESS on success | ||
| 1111 | @retval DB_TABLESPACE_DELETED if the tablespace does not exist */ | ||
| 1112 | [[nodiscard]] dberr_t do_io(const IORequest &type, bool sync, | ||
| 1113 | const page_id_t &page_id, | ||
| 1114 | const page_size_t &page_size, ulint byte_offset, | ||
| 1115 | ulint len, void *buf, void *message, trx_t *trx, | ||
| 1116 | bool should_buffer); | ||
| 1117 | |||
| 1118 | /** Iterate through all persistent tablespace files (FIL_TYPE_TABLESPACE) | ||
| 1119 | returning the nodes via callback function f. | ||
| 1120 | @param[in] f Callback | ||
| 1121 | @return any error returned by the callback function. */ | ||
| 1122 | [[nodiscard]] dberr_t iterate(Fil_iterator::Function &f); | ||
| 1123 | |||
| 1124 | /** Open an ibd tablespace and add it to the InnoDB data structures. | ||
| 1125 | This is similar to fil_ibd_open() except that it is used while | ||
| 1126 | processing the redo and DDL log, so the data dictionary is not | ||
| 1127 | available and very little validation is done. The tablespace name | ||
| 1128 | is extracted from the dbname/tablename.ibd portion of the filename, | ||
| 1129 | which assumes that the file is a file-per-table tablespace. Any name | ||
| 1130 | will do for now. General tablespace names will be read from the | ||
| 1131 | dictionary after it has been recovered. The tablespace flags are read | ||
| 1132 | at this time from the first page of the file in validate_for_recovery(). | ||
| 1133 | @param[in] space_id tablespace ID | ||
| 1134 | @param[in] path path/to/databasename/tablename.ibd | ||
| 1135 | @param[out] space the tablespace, or nullptr on error | ||
| 1136 | @return status of the operation */ | ||
| 1137 | [[nodiscard]] fil_load_status ibd_open_for_recovery(space_id_t space_id, | ||
| 1138 | const std::string &path, | ||
| 1139 | fil_space_t *&space); | ||
| 1140 | |||
| 1141 | /** Attach a file to a tablespace | ||
| 1142 | @param[in] name file name of a file that is not open | ||
| 1143 | @param[in] size file size in entire database blocks | ||
| 1144 | @param[in,out] space tablespace from fil_space_create() | ||
| 1145 | @param[in] is_raw whether this is a raw device or partition | ||
| 1146 | @param[in] punch_hole true if supported for this file | ||
| 1147 | @param[in] atomic_write true if the file has atomic write enabled | ||
| 1148 | @param[in] max_pages maximum number of pages in file | ||
| 1149 | @return pointer to the file name | ||
| 1150 | @retval nullptr if error */ | ||
| 1151 | [[nodiscard]] fil_node_t *create_node(const char *name, page_no_t size, | ||
| 1152 | fil_space_t *space, bool is_raw, | ||
| 1153 | bool punch_hole, bool atomic_write, | ||
| 1154 | page_no_t max_pages = PAGE_NO_MAX); | ||
| 1155 | |||
| 1156 | #ifdef UNIV_DEBUG | ||
| 1157 | /** Validate a shard. */ | ||
| 1158 | void validate() const; | ||
| 1159 | #endif /* UNIV_DEBUG */ | ||
| 1160 | |||
| 1161 | #ifdef UNIV_HOTBACKUP | ||
| 1162 | /** Extends all tablespaces to the size stored in the space header. | ||
| 1163 | During the mysqlbackup --apply-log phase we extended the spaces | ||
| 1164 | on-demand so that log records could be applied, but that may have | ||
| 1165 | left spaces still too small compared to the size stored in the space | ||
| 1166 | header. */ | ||
| 1167 | void meb_extend_tablespaces_to_stored_len(); | ||
| 1168 | #endif /* UNIV_HOTBACKUP */ | ||
| 1169 | |||
| 1170 | /** Free a tablespace object on which fil_space_detach() was invoked. | ||
| 1171 | There must not be any pending I/O's or flushes on the files. | ||
| 1172 | @param[in,out] space tablespace */ | ||
| 1173 | static void space_free_low(fil_space_t *&space); | ||
| 1174 | |||
| 1175 | private: | ||
| 1176 | /** We keep system tablespace files always open; this is important | ||
| 1177 | in preventing deadlocks in this module, as a page read completion | ||
| 1178 | often performs another read from the insert buffer. The insert buffer | ||
| 1179 | is in tablespace TRX_SYS_SPACE, and we cannot end up waiting in this | ||
| 1180 | function. | ||
| 1181 | @param[in] space_id Tablespace ID to look up | ||
| 1182 | @return tablespace instance */ | ||
| 1183 | [[nodiscard]] fil_space_t *get_reserved_space(space_id_t space_id); | ||
| 1184 | |||
| 1185 | /** Prepare for truncating a single-table tablespace. | ||
| 1186 | 1) Wait for pending operations on the tablespace to stop; | ||
| 1187 | 2) Remove all insert buffer entries for the tablespace; | ||
| 1188 | @param[in] space_id Tablespace ID | ||
| 1189 | @param[out] space Instance that maps to the space ID. | ||
| 1190 | @return DB_SUCCESS or error */ | ||
| 1191 | [[nodiscard]] dberr_t space_prepare_for_truncate(space_id_t space_id, | ||
| 1192 | fil_space_t *&space); | ||
| 1193 | |||
| 1194 | /** Note that a write IO has completed. | ||
| 1195 | @param[in,out] file File on which a write was completed */ | ||
| 1196 | void write_completed(fil_node_t *file); | ||
| 1197 | |||
| 1198 | /** If the tablespace is not on the unflushed list, add it. | ||
| 1199 | @param[in,out] space Tablespace to add */ | ||
| 1200 | void add_to_unflushed_list(fil_space_t *space); | ||
| 1201 | |||
| 1202 | /** Check for pending operations. | ||
| 1203 | @param[in] space tablespace | ||
| 1204 | @param[in] count number of attempts so far | ||
| 1205 | @return 0 if no pending operations else count + 1. */ | ||
| 1206 | [[nodiscard]] ulint space_check_pending_operations(fil_space_t *space, | ||
| 1207 | ulint count) const; | ||
| 1208 | |||
| 1209 | /** Check for pending IO. | ||
| 1210 | @param[in] space Tablespace to check | ||
| 1211 | @param[in] file File in space list | ||
| 1212 | @param[in] count number of attempts so far | ||
| 1213 | @return 0 if no pending else count + 1. */ | ||
| 1214 | [[nodiscard]] ulint check_pending_io(const fil_space_t *space, | ||
| 1215 | const fil_node_t &file, | ||
| 1216 | ulint count) const; | ||
| 1217 | |||
| 1218 | /** First we open the file in the normal mode, no async I/O here, for | ||
| 1219 | simplicity. Then do some checks, and close the file again. NOTE that we | ||
| 1220 | could not use the simple file read function os_file_read() in Windows | ||
| 1221 | to read from a file opened for async I/O! | ||
| 1222 | @param[in,out] file Get the size of this file | ||
| 1223 | @param[in] read_only_mode true if read only mode set | ||
| 1224 | @return DB_SUCCESS or error */ | ||
| 1225 | [[nodiscard]] dberr_t get_file_size(fil_node_t *file, bool read_only_mode); | ||
| 1226 | |||
| 1227 | /** Get the AIO mode. | ||
| 1228 | @param[in] req_type IO request type | ||
| 1229 | @param[in] sync true if Synchronous IO | ||
| 1230 | return the AIO mode */ | ||
| 1231 | [[nodiscard]] static AIO_mode get_AIO_mode(const IORequest &req_type, | ||
| 1232 | bool sync); | ||
| 1233 | |||
| 1234 | /** Get the file name for IO and the local offset within that file. | ||
| 1235 | @param[in,out] space Tablespace for IO | ||
| 1236 | @param[in,out] page_no The relative page number in the file | ||
| 1237 | @param[out] file File node if DB_SUCCESS, NULL if not | ||
| 1238 | @retval DB_SUCCESS if the file is found with the page_no | ||
| 1239 | @retval DB_ERROR if the file is not found or does not contain the page. | ||
| 1240 | in this case file == nullptr */ | ||
| 1241 | [[nodiscard]] static dberr_t get_file_for_io(fil_space_t *space, | ||
| 1242 | page_no_t *page_no, | ||
| 1243 | fil_node_t *&file); | ||
| 1244 | |||
| 1245 | private: | ||
| 1246 | /** Fil_shard ID */ | ||
| 1247 | const size_t m_id; | ||
| 1248 | |||
| 1249 | /** Tablespace instances hashed on the space id */ | ||
| 1250 | Spaces m_spaces; | ||
| 1251 | |||
| 1252 | /** Tablespace instances hashed on the space name */ | ||
| 1253 | Names m_names; | ||
| 1254 | |||
| 1255 | #ifndef UNIV_HOTBACKUP | ||
| 1256 | using Pair = std::pair<space_id_t, fil_space_t *>; | ||
| 1257 | using Deleted_spaces = std::vector<Pair, ut::allocator<Pair>>; | ||
| 1258 | |||
| 1259 | /** Deleted tablespaces. All pages for these tablespaces in the buffer pool | ||
| 1260 | will be passively deleted. They need not be written. Once the reference count | ||
| 1261 | is zero, this fil_space_t can be deleted from m_deleted_spaces and removed | ||
| 1262 | from memory. All reads and writes must be done under the shard mutex. */ | ||
| 1263 | Deleted_spaces m_deleted_spaces; | ||
| 1264 | #endif /* !UNIV_HOTBACKUP */ | ||
| 1265 | |||
| 1266 | /** Base node for the LRU list of the most recently used open | ||
| 1267 | files with no pending I/O's; if we start an I/O on the file, | ||
| 1268 | we first remove it from this list, and return it to the start | ||
| 1269 | of the list when the I/O ends; the system tablespace file is | ||
| 1270 | not put to this list: it is opened after the startup, and kept | ||
| 1271 | open until shutdown */ | ||
| 1272 | |||
| 1273 | File_list m_LRU; | ||
| 1274 | |||
| 1275 | /** Base node for the list of those tablespaces whose files contain unflushed | ||
| 1276 | writes; those spaces have at least one file where modification_counter > | ||
| 1277 | flush_counter */ | ||
| 1278 | Space_list m_unflushed_spaces; | ||
| 1279 | |||
| 1280 | /** When we write to a file we increment this by one */ | ||
| 1281 | int64_t m_modification_counter; | ||
| 1282 | |||
| 1283 | /** Mutex protecting this shard. */ | ||
| 1284 | #ifndef UNIV_HOTBACKUP | ||
| 1285 | mutable ib_mutex_t m_mutex; | ||
| 1286 | #else | ||
| 1287 | mutable meb::Mutex m_mutex; | ||
| 1288 | #endif /* !UNIV_HOTBACKUP */ | ||
| 1289 | |||
| 1290 | // Disable copying | ||
| 1291 | Fil_shard(Fil_shard &&) = delete; | ||
| 1292 | Fil_shard(const Fil_shard &) = delete; | ||
| 1293 | Fil_shard &operator=(Fil_shard &&) = delete; | ||
| 1294 | Fil_shard &operator=(const Fil_shard &) = delete; | ||
| 1295 | |||
| 1296 | friend class Fil_system; | ||
| 1297 | |||
| 1298 | public: | ||
| 1299 | // list of spaces kept in this shard | ||
| 1300 | Full_space_list m_space_list; | ||
| 1301 | Rotation_list m_rotation_list; | ||
| 1302 | }; | ||
| 1303 | |||
| 1304 | /** The tablespace memory cache */ | ||
| 1305 | class Fil_system { | ||
| 1306 | public: | ||
| 1307 | using Fil_shards = std::vector<Fil_shard *>; | ||
| 1308 | |||
| 1309 | /** Constructor. | ||
| 1310 | @param[in] n_shards Number of shards to create | ||
| 1311 | @param[in] max_open Maximum number of open files */ | ||
| 1312 | Fil_system(size_t n_shards, size_t max_open); | ||
| 1313 | |||
| 1314 | /** Destructor */ | ||
| 1315 | ~Fil_system(); | ||
| 1316 | |||
| 1317 | /** Acquire a tablespace when it could be dropped concurrently. | ||
| 1318 | Used by background threads that do not necessarily hold proper locks | ||
| 1319 | for concurrency control. | ||
| 1320 | @param[in] space_id Tablespace ID | ||
| 1321 | @param[in] silent Whether to silently ignore missing tablespaces | ||
| 1322 | @return the tablespace, or nullptr if missing or being deleted */ | ||
| 1323 | fil_space_t *space_acquire(space_id_t space_id, bool silent); | ||
| 1324 | |||
| 1325 | /** Fetch the file names opened for a space_id during recovery. | ||
| 1326 | @param[in] space_id Tablespace ID to lookup | ||
| 1327 | @return pair of top level directory scanned and names that map | ||
| 1328 | to space_id or nullptr if not found. */ | ||
| 1329 | 18918891 | [[nodiscard]] Tablespace_dirs::Result get_scanned_filename_by_space_id( | |
| 1330 | space_id_t space_id) { | ||
| 1331 | 18918891 | return m_dirs.find_by_id(space_id); | |
| 1332 | } | ||
| 1333 | |||
| 1334 | /** Fetch the file name opened for an undo space number. | ||
| 1335 | @param[in] space_num undo tablespace numb er to lookup | ||
| 1336 | @param[out] space_id Tablespace ID found | ||
| 1337 | @return pair of top level directory scanned and name that maps | ||
| 1338 | to the space_num or nullptr if not found. */ | ||
| 1339 | 1196733 | [[nodiscard]] Tablespace_dirs::Result get_scanned_filename_by_space_num( | |
| 1340 | space_id_t space_num, space_id_t &space_id) { | ||
| 1341 | 1196733 | return (m_dirs.find_by_num(space_num, space_id)); | |
| 1342 | } | ||
| 1343 | |||
| 1344 | /** Fetch the file name opened for a space_id from the file map. | ||
| 1345 | @param[in] space_id tablespace ID | ||
| 1346 | @param[out] name the scanned filename | ||
| 1347 | @return true if the space_id is found. The name is set to an | ||
| 1348 | empty string if the space_id is not found. */ | ||
| 1349 | 4 | [[nodiscard]] bool get_file_by_space_id(space_id_t space_id, | |
| 1350 | std::string &name) { | ||
| 1351 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | auto result = get_scanned_filename_by_space_id(space_id); |
| 1352 | |||
| 1353 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (result.second != nullptr) { |
| 1354 | /* Duplicates should have been sorted out by now. */ | ||
| 1355 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | ut_a(result.second->size() == 1); |
| 1356 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | name = result.first + result.second->front(); |
| 1357 | 4 | return true; | |
| 1358 | } | ||
| 1359 | |||
| 1360 | ✗ | name = ""; | |
| 1361 | ✗ | return false; | |
| 1362 | 4 | } | |
| 1363 | |||
| 1364 | /** Fetch the file name opened for an undo space number. | ||
| 1365 | @param[in] space_num undo tablespace number | ||
| 1366 | @param[out] space_id tablespace ID | ||
| 1367 | @param[out] name the scanned filename | ||
| 1368 | @return true if the space_id is found. The name is set to an | ||
| 1369 | empty string if the space_id is not found. */ | ||
| 1370 | 1196733 | [[nodiscard]] bool get_file_by_space_num(space_id_t space_num, | |
| 1371 | space_id_t &space_id, | ||
| 1372 | std::string &name) { | ||
| 1373 |
1/2✓ Branch 0 taken 1196733 times.
✗ Branch 1 not taken.
|
1196733 | auto result = get_scanned_filename_by_space_num(space_num, space_id); |
| 1374 | |||
| 1375 |
2/2✓ Branch 0 taken 18950 times.
✓ Branch 1 taken 1177783 times.
|
1196733 | if (result.second != nullptr) { |
| 1376 | /* Duplicates should have been sorted out by now. */ | ||
| 1377 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18950 times.
|
18950 | ut_a(result.second->size() == 1); |
| 1378 |
1/2✓ Branch 0 taken 18950 times.
✗ Branch 1 not taken.
|
18950 | name = result.first + result.second->front(); |
| 1379 | 18950 | return true; | |
| 1380 | } | ||
| 1381 | |||
| 1382 |
1/2✓ Branch 0 taken 1177783 times.
✗ Branch 1 not taken.
|
1177783 | name = ""; |
| 1383 | 1177783 | return false; | |
| 1384 | 1196733 | } | |
| 1385 | |||
| 1386 | /** Erase a tablespace ID and its mapping from the scanned files. | ||
| 1387 | @param[in] space_id Tablespace ID to erase | ||
| 1388 | @return true if successful */ | ||
| 1389 | 6 | [[nodiscard]] bool erase_path(space_id_t space_id) { | |
| 1390 | 6 | return m_dirs.erase_path(space_id); | |
| 1391 | } | ||
| 1392 | |||
| 1393 | /** Add file to old file list. The list is used during 5.7 upgrade failure | ||
| 1394 | to revert back the modified file names. We modify partitioned file names | ||
| 1395 | to lower case. | ||
| 1396 | @param[in] file_path old file name with path */ | ||
| 1397 | 407 | void add_old_file(const std::string &file_path) { | |
| 1398 | 407 | m_old_paths.push_back(file_path); | |
| 1399 | 407 | } | |
| 1400 | |||
| 1401 | /** Rename partition files during upgrade. | ||
| 1402 | @param[in] revert if true, revert to old names */ | ||
| 1403 | void rename_partition_files(bool revert); | ||
| 1404 | |||
| 1405 | /** Clear all accumulated old files. */ | ||
| 1406 | 8379 | void clear_old_files() { m_old_paths.clear(); } | |
| 1407 | |||
| 1408 | /** Get the top level directory where this filename was found. | ||
| 1409 | @param[in] path Path to look for. | ||
| 1410 | @return the top level directory under which this file was found. */ | ||
| 1411 | [[nodiscard]] const std::string &get_root(const std::string &path) const; | ||
| 1412 | |||
| 1413 | /** Update the DD if any files were moved to a new location. | ||
| 1414 | Free the Tablespace_files instance. | ||
| 1415 | @param[in] read_only_mode true if InnoDB is started in | ||
| 1416 | read only mode. | ||
| 1417 | @return DB_SUCCESS if all OK */ | ||
| 1418 | [[nodiscard]] dberr_t prepare_open_for_business(bool read_only_mode); | ||
| 1419 | |||
| 1420 | /** Flush to disk the writes in file spaces possibly cached by the OS | ||
| 1421 | (note: spaces of type FIL_TYPE_TEMPORARY are skipped) */ | ||
| 1422 | void flush_file_spaces(); | ||
| 1423 | |||
| 1424 | #ifndef UNIV_HOTBACKUP | ||
| 1425 | /** Clean up the shards. */ | ||
| 1426 | 560118 | void purge() { | |
| 1427 |
2/2✓ Branch 0 taken 38088024 times.
✓ Branch 1 taken 560118 times.
|
38648142 | for (auto shard : m_shards) { |
| 1428 |
1/2✓ Branch 0 taken 38088024 times.
✗ Branch 1 not taken.
|
38088024 | shard->purge(); |
| 1429 | } | ||
| 1430 | 560118 | } | |
| 1431 | |||
| 1432 | /** Count how many truncated undo space IDs are still tracked in | ||
| 1433 | the buffer pool and the file_system cache. | ||
| 1434 | @param[in] undo_num undo tablespace number. | ||
| 1435 | @return number of undo tablespaces that are still in memory. */ | ||
| 1436 | 52927 | size_t count_undo_deleted(space_id_t undo_num) { | |
| 1437 | 52927 | size_t count = 0; | |
| 1438 | |||
| 1439 |
2/2✓ Branch 0 taken 3599036 times.
✓ Branch 1 taken 52927 times.
|
3651963 | for (auto shard : m_shards) { |
| 1440 | 3599036 | count += shard->count_undo_deleted(undo_num); | |
| 1441 | } | ||
| 1442 | |||
| 1443 | 52927 | return count; | |
| 1444 | } | ||
| 1445 | |||
| 1446 | /** Check if a particular undo space_id for a page in the buffer pool has | ||
| 1447 | been deleted recently. | ||
| 1448 | Its space_id will be found in Fil_shard::m_deleted_spaces until | ||
| 1449 | Fil:shard::checkpoint removes the fil_space_t from Fil_system. | ||
| 1450 | @param[in] space_id Tablespace ID to check. | ||
| 1451 | @return true if this space_id is in the list of recently deleted spaces. */ | ||
| 1452 | bool is_deleted(space_id_t space_id) noexcept { | ||
| 1453 | auto shard = shard_by_id(space_id); | ||
| 1454 | |||
| 1455 | return shard->is_deleted(space_id); | ||
| 1456 | } | ||
| 1457 | #endif /* !UNIV_HOTBACKUP */ | ||
| 1458 | |||
| 1459 | /** Fetch the fil_space_t instance that maps to the name. | ||
| 1460 | @param[in] name Tablespace name to lookup | ||
| 1461 | @return tablespace instance or nullptr if not found. */ | ||
| 1462 | 154433 | [[nodiscard]] fil_space_t *get_space_by_name(const char *name) { | |
| 1463 |
2/2✓ Branch 0 taken 9434079 times.
✓ Branch 1 taken 1316 times.
|
9435395 | for (auto shard : m_shards) { |
| 1464 |
1/2✓ Branch 0 taken 9434079 times.
✗ Branch 1 not taken.
|
9434079 | shard->mutex_acquire(); |
| 1465 | |||
| 1466 |
1/2✓ Branch 0 taken 9434079 times.
✗ Branch 1 not taken.
|
9434079 | auto space = shard->get_space_by_name(name); |
| 1467 | |||
| 1468 |
1/2✓ Branch 0 taken 9434079 times.
✗ Branch 1 not taken.
|
9434079 | shard->mutex_release(); |
| 1469 | |||
| 1470 |
2/2✓ Branch 0 taken 153117 times.
✓ Branch 1 taken 9280962 times.
|
9434079 | if (space != nullptr) { |
| 1471 | 153117 | return space; | |
| 1472 | } | ||
| 1473 | } | ||
| 1474 | |||
| 1475 | 1316 | return nullptr; | |
| 1476 | } | ||
| 1477 | |||
| 1478 | /** Check a space ID against the maximum known tablespace ID. | ||
| 1479 | @param[in] space_id Tablespace ID to check | ||
| 1480 | @return true if it is > than maximum known tablespace ID. */ | ||
| 1481 | 421744 | [[nodiscard]] bool is_greater_than_max_id(space_id_t space_id) const { | |
| 1482 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 421744 times.
|
421744 | ut_ad(mutex_owned_all()); |
| 1483 | |||
| 1484 | 421744 | return space_id > m_max_assigned_id; | |
| 1485 | } | ||
| 1486 | |||
| 1487 | /** Update the maximum known tablespace ID. | ||
| 1488 | @param[in] space Tablespace instance */ | ||
| 1489 | ✗ | void set_maximum_space_id(const fil_space_t *space) { | |
| 1490 | ✗ | ut_ad(mutex_owned_all()); | |
| 1491 | |||
| 1492 | ✗ | if (!m_space_id_reuse_warned) { | |
| 1493 | ✗ | m_space_id_reuse_warned = true; | |
| 1494 | |||
| 1495 | ✗ | ib::warn(ER_IB_MSG_266) << "Allocated tablespace ID " << space->id | |
| 1496 | ✗ | << " for " << space->name << ", old maximum" | |
| 1497 | ✗ | << " was " << m_max_assigned_id; | |
| 1498 | } | ||
| 1499 | |||
| 1500 | ✗ | m_max_assigned_id = space->id; | |
| 1501 | } | ||
| 1502 | |||
| 1503 | /** Update the maximum known space ID if it's smaller than max_id. | ||
| 1504 | @param[in] space_id Value to set if it's greater */ | ||
| 1505 | 28614 | void update_maximum_space_id(space_id_t space_id) { | |
| 1506 | 28614 | mutex_acquire_all(); | |
| 1507 | |||
| 1508 |
2/2✓ Branch 0 taken 9416 times.
✓ Branch 1 taken 19198 times.
|
28614 | if (is_greater_than_max_id(space_id)) { |
| 1509 | 9416 | m_max_assigned_id = space_id; | |
| 1510 | } | ||
| 1511 | |||
| 1512 | 28614 | mutex_release_all(); | |
| 1513 | 28614 | } | |
| 1514 | |||
| 1515 | /** Assigns a new space id for a new single-table tablespace. This | ||
| 1516 | works simply by incrementing the global counter. If 4 billion ids | ||
| 1517 | is not enough, we may need to recycle ids. | ||
| 1518 | @param[out] space_id Set this to the new tablespace ID | ||
| 1519 | @return true if assigned, false if not */ | ||
| 1520 | [[nodiscard]] bool assign_new_space_id(space_id_t *space_id); | ||
| 1521 | |||
| 1522 | /** Allows other threads to advance work while we wait for I/Os to complete. | ||
| 1523 | */ | ||
| 1524 | ✗ | void wait_while_ios_in_progress() const { | |
| 1525 | #ifndef UNIV_HOTBACKUP | ||
| 1526 | /* Wake the I/O-handler threads to make sure pending I/Os are | ||
| 1527 | performed. */ | ||
| 1528 | ✗ | os_aio_simulated_wake_handler_threads(); | |
| 1529 | #endif /* !UNIV_HOTBACKUP */ | ||
| 1530 | /* Give CPU to other threads that keep files opened. */ | ||
| 1531 | ✗ | std::this_thread::sleep_for(std::chrono::milliseconds(1)); | |
| 1532 | } | ||
| 1533 | |||
| 1534 | /** Tries to close a file in all the LRU lists. | ||
| 1535 | The caller must hold the mutex. | ||
| 1536 | @return true if success, false if should retry later */ | ||
| 1537 | [[nodiscard]] bool close_file_in_all_LRU(); | ||
| 1538 | |||
| 1539 | /** Opens all system tablespace data files in all shards. */ | ||
| 1540 | void open_all_system_tablespaces(); | ||
| 1541 | |||
| 1542 | /** Close all open files. */ | ||
| 1543 | void close_all_files(); | ||
| 1544 | |||
| 1545 | /** Returns maximum number of allowed non-LRU files opened for a specified | ||
| 1546 | open files limit. */ | ||
| 1547 | static size_t get_limit_for_non_lru_files(size_t open_files_limit); | ||
| 1548 | |||
| 1549 | /** Returns minimum open files limit to be set to allow the specified number | ||
| 1550 | of non-LRU files opened. This is inverse function for the | ||
| 1551 | get_limit_for_non_lru_files. */ | ||
| 1552 | size_t get_minimum_limit_for_open_files( | ||
| 1553 | size_t n_files_not_belonging_in_lru) const; | ||
| 1554 | |||
| 1555 | /** Changes the maximum opened files limit. | ||
| 1556 | @param[in,out] new_max_open_files New value for the open files limit. If the | ||
| 1557 | limit cannot be changed, the value is changed to a minimum value recommended. | ||
| 1558 | If there are any concurrent calls to set_open_files_limit in progress, setting | ||
| 1559 | the limit will fail and the new_max_open_files will be set to 0. | ||
| 1560 | @return true if the new limit was set. */ | ||
| 1561 | bool set_open_files_limit(size_t &new_max_open_files); | ||
| 1562 | |||
| 1563 | /** Returns maximum number of allowed opened files. */ | ||
| 1564 | 1619508 | size_t get_open_files_limit() const { return m_open_files_limit.get_limit(); } | |
| 1565 | |||
| 1566 | /** Iterate through all persistent tablespace files | ||
| 1567 | (FIL_TYPE_TABLESPACE) returning the nodes via callback function cbk. | ||
| 1568 | @param[in] f Callback | ||
| 1569 | @return any error returned by the callback function. */ | ||
| 1570 | [[nodiscard]] dberr_t iterate(Fil_iterator::Function &f); | ||
| 1571 | |||
| 1572 | /** Rotate the tablespace keys by new master key. | ||
| 1573 | @return the number of tablespaces that failed to rotate. */ | ||
| 1574 | [[nodiscard]] size_t encryption_rotate(); | ||
| 1575 | |||
| 1576 | /** Reencrypt tablespace keys by current master key. */ | ||
| 1577 | void encryption_reencrypt(std::vector<space_id_t> &sid_vector); | ||
| 1578 | |||
| 1579 | /** Detach a space object from the tablespace memory cache. | ||
| 1580 | Closes the tablespace files but does not delete them. | ||
| 1581 | There must not be any pending I/O's or flushes on the files. | ||
| 1582 | @param[in,out] space tablespace */ | ||
| 1583 | void space_detach(fil_space_t *space); | ||
| 1584 | |||
| 1585 | /** @return the maximum assigned ID so far */ | ||
| 1586 | space_id_t get_max_space_id() const { return m_max_assigned_id; } | ||
| 1587 | |||
| 1588 | /** Lookup the tablespace ID. | ||
| 1589 | @param[in] space_id Tablespace ID to lookup | ||
| 1590 | @return true if the space ID is known. */ | ||
| 1591 | [[nodiscard]] bool lookup_for_recovery(space_id_t space_id); | ||
| 1592 | |||
| 1593 | /** Open a tablespace that has a redo log record to apply. | ||
| 1594 | @param[in] space_id Tablespace ID | ||
| 1595 | @return DB_SUCCESS if the open was successful */ | ||
| 1596 | [[nodiscard]] dberr_t open_for_recovery(space_id_t space_id); | ||
| 1597 | |||
| 1598 | /** This function should be called after recovery has completed. | ||
| 1599 | Check for tablespace files for which we did not see any | ||
| 1600 | MLOG_FILE_DELETE or MLOG_FILE_RENAME record. These could not | ||
| 1601 | be recovered. | ||
| 1602 | @return true if there were some filenames missing for which we had to | ||
| 1603 | ignore redo log records during the apply phase */ | ||
| 1604 | [[nodiscard]] bool check_missing_tablespaces(); | ||
| 1605 | |||
| 1606 | /** Note that a file has been relocated. | ||
| 1607 | @param[in] object_id Server DD tablespace ID | ||
| 1608 | @param[in] space_id InnoDB tablespace ID | ||
| 1609 | @param[in] space_name Tablespace name | ||
| 1610 | @param[in] old_path Path to the old location | ||
| 1611 | @param[in] new_path Path scanned from disk */ | ||
| 1612 | 226 | void moved(dd::Object_id object_id, space_id_t space_id, | |
| 1613 | const char *space_name, const std::string &old_path, | ||
| 1614 | const std::string &new_path) { | ||
| 1615 | auto tuple = | ||
| 1616 |
1/2✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
|
226 | std::make_tuple(object_id, space_id, space_name, old_path, new_path); |
| 1617 | |||
| 1618 |
2/4✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 226 times.
✗ Branch 3 not taken.
|
226 | m_moved.push_back(tuple); |
| 1619 | 226 | } | |
| 1620 | |||
| 1621 | /** Check if a path is known to InnoDB. | ||
| 1622 | @param[in] path Path to check | ||
| 1623 | @return true if path is known to InnoDB */ | ||
| 1624 | 15110 | bool check_path(const std::string &path) const { | |
| 1625 | 15110 | return m_dirs.contains(path); | |
| 1626 | } | ||
| 1627 | |||
| 1628 | /** Get the list of directories that InnoDB knows about. | ||
| 1629 | @return the list of directories 'dir1;dir2;....;dirN' */ | ||
| 1630 | 9693 | std::string get_dirs() const { return m_dirs.get_dirs(); } | |
| 1631 | |||
| 1632 | /** Determines if a file belongs to the least-recently-used list. | ||
| 1633 | @param[in] space Tablespace to check | ||
| 1634 | @return true if the file belongs to fil_system->m_LRU mutex. */ | ||
| 1635 | [[nodiscard]] static bool space_belongs_in_LRU(const fil_space_t *space); | ||
| 1636 | |||
| 1637 | /** Normalize and save a directory to scan for IBD and IBU datafiles | ||
| 1638 | before recovery. | ||
| 1639 | @param[in] directory Directory to scan | ||
| 1640 | @param[in] is_undo_dir true for an undo directory */ | ||
| 1641 | 19433 | void set_scan_dir(const std::string &directory, bool is_undo_dir) { | |
| 1642 | 19433 | m_dirs.set_scan_dir(directory, is_undo_dir); | |
| 1643 | 19433 | } | |
| 1644 | |||
| 1645 | /** Normalize and save a list of directories to scan for IBD and IBU | ||
| 1646 | datafiles before recovery. | ||
| 1647 | @param[in] directories Directories to scan */ | ||
| 1648 | 86 | void set_scan_dirs(const std::string &directories) { | |
| 1649 | 86 | m_dirs.set_scan_dirs(directories); | |
| 1650 | 86 | } | |
| 1651 | |||
| 1652 | /** Scan the directories to build the tablespace ID to file name | ||
| 1653 | mapping table. */ | ||
| 1654 | 9693 | dberr_t scan() { return m_dirs.scan(); } | |
| 1655 | |||
| 1656 | /** Get the tablespace ID from an .ibd and/or an undo tablespace. If the ID is | ||
| 1657 | 0 on the first page then try finding the ID with Datafile::find_space_id(). | ||
| 1658 | @param[in] filename File name to check | ||
| 1659 | @return s_invalid_space_id if not found, otherwise the space ID */ | ||
| 1660 | [[nodiscard]] static space_id_t get_tablespace_id( | ||
| 1661 | const std::string &filename); | ||
| 1662 | |||
| 1663 | /** Fil_shard by space ID. | ||
| 1664 | @param[in] space_id Tablespace ID | ||
| 1665 | @return reference to the shard */ | ||
| 1666 | 8349922787 | [[nodiscard]] Fil_shard *shard_by_id(space_id_t space_id, | |
| 1667 | uint *index = nullptr) const { | ||
| 1668 | #ifndef UNIV_HOTBACKUP | ||
| 1669 |
2/2✓ Branch 0 taken 3006497203 times.
✓ Branch 1 taken 5343647730 times.
|
8349922787 | if (fsp_is_undo_tablespace(space_id)) { |
| 1670 | 3006497203 | const size_t limit = space_id % UNDO_SHARDS; | |
| 1671 | |||
| 1672 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 3006497111 times.
|
3006497203 | if (index) *index = UNDO_SHARDS_START + limit; |
| 1673 | 3006497203 | return m_shards[UNDO_SHARDS_START + limit]; | |
| 1674 | } | ||
| 1675 | |||
| 1676 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5343916395 times.
|
5343647730 | ut_ad(m_shards.size() == MAX_SHARDS); |
| 1677 | |||
| 1678 |
2/2✓ Branch 0 taken 322 times.
✓ Branch 1 taken 5343916073 times.
|
5343916395 | if (index) *index = space_id % UNDO_SHARDS_START; |
| 1679 | 5343916395 | return m_shards[space_id % UNDO_SHARDS_START]; | |
| 1680 | #else /* !UNIV_HOTBACKUP */ | ||
| 1681 | ut_ad(m_shards.size() == 1); | ||
| 1682 | |||
| 1683 | return m_shards[0]; | ||
| 1684 | #endif /* !UNIV_HOTBACKUP */ | ||
| 1685 | } | ||
| 1686 | |||
| 1687 | 3130 | MY_NODISCARD Fil_shard *shard_by_index(const uint index) const { | |
| 1688 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3130 times.
|
3130 | ut_ad(index < m_shards.size()); |
| 1689 | 3130 | return m_shards[index]; | |
| 1690 | } | ||
| 1691 | |||
| 1692 | 3128 | uint get_number_of_shards() const { return m_shards.size(); } | |
| 1693 | |||
| 1694 | /** Acquire all the mutexes. */ | ||
| 1695 | 628392 | void mutex_acquire_all() const { | |
| 1696 | #ifdef UNIV_HOTBACKUP | ||
| 1697 | ut_ad(m_shards.size() == 1); | ||
| 1698 | #endif /* UNIV_HOTBACKUP */ | ||
| 1699 | |||
| 1700 |
2/2✓ Branch 0 taken 42730656 times.
✓ Branch 1 taken 628392 times.
|
43359048 | for (auto shard : m_shards) { |
| 1701 |
1/2✓ Branch 0 taken 42730656 times.
✗ Branch 1 not taken.
|
42730656 | shard->mutex_acquire(); |
| 1702 | } | ||
| 1703 | 628392 | } | |
| 1704 | |||
| 1705 | /** Release all the mutexes. */ | ||
| 1706 | 628392 | void mutex_release_all() const { | |
| 1707 | #ifdef UNIV_HOTBACKUP | ||
| 1708 | ut_ad(m_shards.size() == 1); | ||
| 1709 | #endif /* UNIV_HOTBACKUP */ | ||
| 1710 | |||
| 1711 |
2/2✓ Branch 0 taken 42730656 times.
✓ Branch 1 taken 628392 times.
|
43359048 | for (auto shard : m_shards) { |
| 1712 |
1/2✓ Branch 0 taken 42730656 times.
✗ Branch 1 not taken.
|
42730656 | shard->mutex_release(); |
| 1713 | } | ||
| 1714 | 628392 | } | |
| 1715 | |||
| 1716 | #ifdef UNIV_DEBUG | ||
| 1717 | |||
| 1718 | /** Checks the consistency of the tablespace cache. | ||
| 1719 | @return true if ok */ | ||
| 1720 | [[nodiscard]] bool validate() const; | ||
| 1721 | |||
| 1722 | /** Check if all mutexes are owned | ||
| 1723 | @return true if all owned. */ | ||
| 1724 | 421744 | [[nodiscard]] bool mutex_owned_all() const { | |
| 1725 | #ifdef UNIV_HOTBACKUP | ||
| 1726 | ut_ad(m_shards.size() == 1); | ||
| 1727 | #endif /* UNIV_HOTBACKUP */ | ||
| 1728 | |||
| 1729 |
2/2✓ Branch 0 taken 28678592 times.
✓ Branch 1 taken 421744 times.
|
29100336 | for (const auto shard : m_shards) { |
| 1730 |
2/4✓ Branch 0 taken 28678592 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 28678592 times.
|
28678592 | ut_ad(shard->mutex_owned()); |
| 1731 | } | ||
| 1732 | |||
| 1733 | 421744 | return true; | |
| 1734 | } | ||
| 1735 | |||
| 1736 | #endif /* UNIV_DEBUG */ | ||
| 1737 | |||
| 1738 | /** Rename a tablespace. Use the space_id to find the shard. | ||
| 1739 | @param[in] space_id tablespace ID | ||
| 1740 | @param[in] old_name old tablespace name | ||
| 1741 | @param[in] new_name new tablespace name | ||
| 1742 | @return DB_SUCCESS on success */ | ||
| 1743 | [[nodiscard]] dberr_t rename_tablespace_name(space_id_t space_id, | ||
| 1744 | const char *old_name, | ||
| 1745 | const char *new_name); | ||
| 1746 | |||
| 1747 | /** Free the data structures required for recovery. */ | ||
| 1748 | 9493 | void free_scanned_files() { m_dirs.clear(); } | |
| 1749 | |||
| 1750 | #ifdef UNIV_HOTBACKUP | ||
| 1751 | /** Extends all tablespaces to the size stored in the space header. | ||
| 1752 | During the mysqlbackup --apply-log phase we extended the spaces | ||
| 1753 | on-demand so that log records could be applied, but that may have | ||
| 1754 | left spaces still too small compared to the size stored in the space | ||
| 1755 | header. */ | ||
| 1756 | void meb_extend_tablespaces_to_stored_len() { | ||
| 1757 | ut_ad(m_shards.size() == 1); | ||
| 1758 | |||
| 1759 | /* We use a single shard for MEB. */ | ||
| 1760 | auto shard = shard_by_id(SPACE_UNKNOWN); | ||
| 1761 | |||
| 1762 | shard->mutex_acquire(); | ||
| 1763 | |||
| 1764 | shard->meb_extend_tablespaces_to_stored_len(); | ||
| 1765 | |||
| 1766 | shard->mutex_release(); | ||
| 1767 | } | ||
| 1768 | |||
| 1769 | /** Process a file name passed as an input | ||
| 1770 | Wrapper around meb_name_process() | ||
| 1771 | @param[in,out] name absolute path of tablespace file | ||
| 1772 | @param[in] space_id The tablespace ID | ||
| 1773 | @param[in] deleted true if MLOG_FILE_DELETE */ | ||
| 1774 | void meb_name_process(char *name, space_id_t space_id, bool deleted); | ||
| 1775 | |||
| 1776 | } | ||
| 1777 | #endif /* UNIV_HOTBACKUP */ | ||
| 1778 | |||
| 1779 | private: | ||
| 1780 | /** Open an ibd tablespace and add it to the InnoDB data structures. | ||
| 1781 | This is similar to fil_ibd_open() except that it is used while | ||
| 1782 | processing the redo log, so the data dictionary is not available | ||
| 1783 | and very little validation is done. The tablespace name is extracted | ||
| 1784 | from the dbname/tablename.ibd portion of the filename, which assumes | ||
| 1785 | that the file is a file-per-table tablespace. Any name will do for | ||
| 1786 | now. General tablespace names will be read from the dictionary after | ||
| 1787 | it has been recovered. The tablespace flags are read at this time | ||
| 1788 | from the first page of the file in validate_for_recovery(). | ||
| 1789 | @param[in] space_id tablespace ID | ||
| 1790 | @param[in] path path/to/databasename/tablename.ibd | ||
| 1791 | @param[out] space the tablespace, or nullptr on error | ||
| 1792 | @return status of the operation */ | ||
| 1793 | [[nodiscard]] fil_load_status ibd_open_for_recovery(space_id_t space_id, | ||
| 1794 | const std::string &path, | ||
| 1795 | fil_space_t *&space); | ||
| 1796 | |||
| 1797 | private: | ||
| 1798 | /** Fil_shards managed */ | ||
| 1799 | Fil_shards m_shards; | ||
| 1800 | |||
| 1801 | fil::detail::Open_files_limit m_open_files_limit; | ||
| 1802 | |||
| 1803 | /** Maximum space id in the existing tables, or assigned during | ||
| 1804 | the time mysqld has been up; at an InnoDB startup we scan the | ||
| 1805 | data dictionary and set here the maximum of the space id's of | ||
| 1806 | the tables there */ | ||
| 1807 | space_id_t m_max_assigned_id; | ||
| 1808 | |||
| 1809 | /** true if fil_space_create() has issued a warning about | ||
| 1810 | potential space_id reuse */ | ||
| 1811 | bool m_space_id_reuse_warned; | ||
| 1812 | |||
| 1813 | /** List of tablespaces that have been relocated. We need to | ||
| 1814 | update the DD when it is safe to do so. */ | ||
| 1815 | dd_fil::Tablespaces m_moved; | ||
| 1816 | |||
| 1817 | /** Tablespace directories scanned at startup */ | ||
| 1818 | Tablespace_dirs m_dirs; | ||
| 1819 | |||
| 1820 | /** Old file paths during 5.7 upgrade. */ | ||
| 1821 | std::vector<std::string> m_old_paths; | ||
| 1822 | |||
| 1823 | /** Next index (modulo number of shards) to try to close a file from the LRU | ||
| 1824 | list to distribute closures evenly between the shards. */ | ||
| 1825 | std::atomic_size_t m_next_shard_to_close_from_LRU{}; | ||
| 1826 | |||
| 1827 | /** Current number of files that are not belonging in LRU. This includes redo | ||
| 1828 | and temporary tablespaces, but not files that were temporarily removed from | ||
| 1829 | the LRU for I/O. */ | ||
| 1830 | std::atomic_size_t m_n_files_not_belonging_in_lru{}; | ||
| 1831 | |||
| 1832 | /** Throttles messages about high files not belonging in LRU count, the | ||
| 1833 | warning ER_IB_WARN_MANY_NON_LRU_FILES_OPENED. */ | ||
| 1834 | ib::Throttler m_MANY_NON_LRU_FILES_OPENED_throttler{}; | ||
| 1835 | /** Throttles messages about long waiting for opened files limit, the warning | ||
| 1836 | ER_IB_MSG_TRYING_TO_OPEN_FILE_FOR_LONG_TIME. */ | ||
| 1837 | ib::Throttler m_TRYING_TO_OPEN_FILE_FOR_LONG_TIME_throttler{}; | ||
| 1838 | /** Throttles messages about accessing space that was already removed, the | ||
| 1839 | warning ACCESSING_NONEXISTINC_SPACE. */ | ||
| 1840 | ib::Throttler m_ACCESSING_NONEXISTINC_SPACE_throttler{}; | ||
| 1841 | |||
| 1842 | // Disable copying | ||
| 1843 | Fil_system(Fil_system &&) = delete; | ||
| 1844 | Fil_system(const Fil_system &) = delete; | ||
| 1845 | Fil_system &operator=(const Fil_system &) = delete; | ||
| 1846 | |||
| 1847 | friend class Fil_shard; | ||
| 1848 | }; | ||
| 1849 | |||
| 1850 | /** The tablespace memory cache. This variable is nullptr before the module is | ||
| 1851 | initialized. */ | ||
| 1852 | static Fil_system *fil_system = nullptr; | ||
| 1853 | |||
| 1854 | #ifdef UNIV_HOTBACKUP | ||
| 1855 | static ulint srv_data_read; | ||
| 1856 | static ulint srv_data_written; | ||
| 1857 | #endif /* UNIV_HOTBACKUP */ | ||
| 1858 | |||
| 1859 | 9986813 | static bool is_fast_shutdown() { | |
| 1860 | #ifndef UNIV_HOTBACKUP | ||
| 1861 |
2/2✓ Branch 0 taken 314542 times.
✓ Branch 1 taken 9672292 times.
|
10301355 | return srv_shutdown_state >= SRV_SHUTDOWN_LAST_PHASE && |
| 1862 |
2/2✓ Branch 0 taken 176 times.
✓ Branch 1 taken 314366 times.
|
10301376 | srv_fast_shutdown >= 2; |
| 1863 | #else | ||
| 1864 | return false; | ||
| 1865 | #endif | ||
| 1866 | } | ||
| 1867 | |||
| 1868 | 445861 | bool fil_node_t::can_be_closed() const { | |
| 1869 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 445860 times.
|
445861 | ut_ad(is_open); |
| 1870 | /* We need to wait for the pending extension and I/Os to finish. */ | ||
| 1871 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 445860 times.
|
445860 | if (n_pending_ios != 0) { |
| 1872 | ✗ | return false; | |
| 1873 | } | ||
| 1874 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 445857 times.
|
445860 | if (n_pending_flushes != 0) { |
| 1875 | 3 | return false; | |
| 1876 | } | ||
| 1877 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 445857 times.
|
445857 | if (is_being_extended) { |
| 1878 | ✗ | return false; | |
| 1879 | } | ||
| 1880 | #ifndef UNIV_HOTBACKUP | ||
| 1881 | /* The file must be flushed, unless we are in very fast shutdown process. */ | ||
| 1882 |
2/2✓ Branch 0 taken 176 times.
✓ Branch 1 taken 445681 times.
|
445857 | if (is_fast_shutdown()) { |
| 1883 | 176 | return true; | |
| 1884 | } | ||
| 1885 | #endif | ||
| 1886 | 445681 | return is_flushed(); | |
| 1887 | } | ||
| 1888 | |||
| 1889 | /** Replay a file rename operation if possible. | ||
| 1890 | @param[in] page_id Space ID and first page number in the file | ||
| 1891 | @param[in] old_name old file name | ||
| 1892 | @param[in] new_name new file name | ||
| 1893 | @return whether the operation was successfully applied (the name did not exist, | ||
| 1894 | or new_name did not exist and name was successfully renamed to new_name) */ | ||
| 1895 | [[nodiscard]] static bool fil_op_replay_rename(const page_id_t &page_id, | ||
| 1896 | const std::string &old_name, | ||
| 1897 | const std::string &new_name); | ||
| 1898 | |||
| 1899 | #ifndef UNIV_HOTBACKUP | ||
| 1900 | /** Rename partition file. | ||
| 1901 | @param[in] old_path old file path | ||
| 1902 | @param[in] extn file extension suffix | ||
| 1903 | @param[in] revert if true, rename from new to old file | ||
| 1904 | @param[in] import if called during import */ | ||
| 1905 | static void fil_rename_partition_file(const std::string &old_path, | ||
| 1906 | ib_file_suffix extn, bool revert, | ||
| 1907 | bool import); | ||
| 1908 | #endif /* !UNIV_HOTBACKUP */ | ||
| 1909 | |||
| 1910 | /** Get modified name for partition file. During upgrade we change all | ||
| 1911 | partition files to have lower case separator and partition name. | ||
| 1912 | @param[in] old_path old file name and path | ||
| 1913 | @param[in] extn file extension suffix | ||
| 1914 | @param[out] new_path modified new name for partitioned file | ||
| 1915 | @return true, iff name needs modification. */ | ||
| 1916 | static bool fil_get_partition_file(const std::string &old_path, | ||
| 1917 | ib_file_suffix extn, std::string &new_path); | ||
| 1918 | |||
| 1919 | #ifdef UNIV_DEBUG | ||
| 1920 | /** Try fil_validate() every this many times */ | ||
| 1921 | static const size_t FIL_VALIDATE_SKIP = 17; | ||
| 1922 | /** Checks the consistency of the tablespace cache some of the time. | ||
| 1923 | @return true if ok or the check was skipped */ | ||
| 1924 | 146214876 | static bool fil_validate_skip() { | |
| 1925 | /** The fil_validate() call skip counter. Use a signed type | ||
| 1926 | because of the race condition below. */ | ||
| 1927 | #ifdef UNIV_HOTBACKUP | ||
| 1928 | static meb::Mutex meb_mutex; | ||
| 1929 | |||
| 1930 | meb_mutex.lock(); | ||
| 1931 | #endif /* UNIV_HOTBACKUP */ | ||
| 1932 | static int fil_validate_count = FIL_VALIDATE_SKIP; | ||
| 1933 | |||
| 1934 | /* There is a race condition below, but it does not matter, | ||
| 1935 | because this call is only for heuristic purposes. We want to | ||
| 1936 | reduce the call frequency of the costly fil_validate() check | ||
| 1937 | in debug builds. */ | ||
| 1938 | 146214876 | --fil_validate_count; | |
| 1939 | |||
| 1940 |
2/2✓ Branch 0 taken 137621010 times.
✓ Branch 1 taken 8593866 times.
|
146214876 | if (fil_validate_count > 0) { |
| 1941 | #ifdef UNIV_HOTBACKUP | ||
| 1942 | meb_mutex.unlock(); | ||
| 1943 | #endif /* UNIV_HOTBACKUP */ | ||
| 1944 | 137621010 | return true; | |
| 1945 | } | ||
| 1946 | |||
| 1947 | 8593866 | fil_validate_count = FIL_VALIDATE_SKIP; | |
| 1948 | #ifdef UNIV_HOTBACKUP | ||
| 1949 | meb_mutex.unlock(); | ||
| 1950 | #endif /* UNIV_HOTBACKUP */ | ||
| 1951 | |||
| 1952 | 8593866 | return fil_validate(); | |
| 1953 | } | ||
| 1954 | |||
| 1955 | /** Validate a shard */ | ||
| 1956 | 587082333 | void Fil_shard::validate() const { | |
| 1957 | 587082333 | mutex_acquire(); | |
| 1958 | |||
| 1959 | 587077328 | size_t n_open = 0; | |
| 1960 | |||
| 1961 |
2/2✓ Branch 0 taken 282994094 times.
✓ Branch 1 taken 587072691 times.
|
870069804 | for (auto elem : m_spaces) { |
| 1962 | 282994457 | page_no_t size = 0; | |
| 1963 | 282994457 | auto space = elem.second; | |
| 1964 | |||
| 1965 |
2/2✓ Branch 0 taken 282976399 times.
✓ Branch 1 taken 282986285 times.
|
565971119 | for (const auto &file : space->files) { |
| 1966 |
4/6✓ Branch 0 taken 32200839 times.
✓ Branch 1 taken 250775448 times.
✓ Branch 2 taken 32200839 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 282976383 times.
|
282976287 | ut_a(file.is_open || !file.n_pending_ios); |
| 1967 | |||
| 1968 |
2/2✓ Branch 0 taken 250776058 times.
✓ Branch 1 taken 32200325 times.
|
282976383 | if (file.is_open) { |
| 1969 | 250776058 | ++n_open; | |
| 1970 | } | ||
| 1971 | |||
| 1972 | 282976383 | size += file.size; | |
| 1973 | } | ||
| 1974 | |||
| 1975 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 282992476 times.
|
282986285 | ut_a(space->size == size); |
| 1976 | } | ||
| 1977 | |||
| 1978 |
1/2✓ Branch 0 taken 587071384 times.
✗ Branch 1 not taken.
|
587072691 | UT_LIST_CHECK(m_LRU); |
| 1979 | |||
| 1980 |
6/10✓ Branch 0 taken 587071910 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 587071586 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 221337727 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 808408919 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 221337837 times.
✓ Branch 9 taken 587071082 times.
|
808408849 | for (auto file : m_LRU) { |
| 1981 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 221337319 times.
|
221337849 | ut_a(file->is_open); |
| 1982 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 221336125 times.
|
221337319 | ut_a(file->n_pending_ios == 0); |
| 1983 |
2/4✓ Branch 0 taken 221337810 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 221337465 times.
|
221336125 | ut_a(fil_system->space_belongs_in_LRU(file->space)); |
| 1984 | } | ||
| 1985 | |||
| 1986 | 587071082 | mutex_release(); | |
| 1987 | 587088359 | } | |
| 1988 | |||
| 1989 | /** Checks the consistency of the tablespace cache. | ||
| 1990 | @return true if ok */ | ||
| 1991 | 8632286 | bool Fil_system::validate() const { | |
| 1992 |
2/2✓ Branch 0 taken 587082535 times.
✓ Branch 1 taken 8633692 times.
|
595720706 | for (const auto shard : m_shards) { |
| 1993 |
1/2✓ Branch 0 taken 587088420 times.
✗ Branch 1 not taken.
|
587083074 | shard->validate(); |
| 1994 | } | ||
| 1995 | |||
| 1996 | 8633692 | return true; | |
| 1997 | } | ||
| 1998 | /** Checks the consistency of the tablespace cache. | ||
| 1999 | @return true if ok */ | ||
| 2000 | 8632290 | bool fil_validate() { return fil_system->validate(); } | |
| 2001 | #endif /* UNIV_DEBUG */ | ||
| 2002 | |||
| 2003 | /** Constructor. | ||
| 2004 | @param[in] n_shards Number of shards to create | ||
| 2005 | @param[in] max_open Maximum number of open files */ | ||
| 2006 | 9805 | Fil_system::Fil_system(size_t n_shards, size_t max_open) | |
| 2007 | 9805 | : m_shards(), | |
| 2008 |
1/2✓ Branch 0 taken 9805 times.
✗ Branch 1 not taken.
|
9805 | m_open_files_limit(max_open), |
| 2009 | 9805 | m_max_assigned_id(), | |
| 2010 | 9805 | m_space_id_reuse_warned() { | |
| 2011 |
2/2✓ Branch 0 taken 666740 times.
✓ Branch 1 taken 9805 times.
|
676545 | for (size_t i = 0; i < n_shards; ++i) { |
| 2012 |
1/2✓ Branch 0 taken 666740 times.
✗ Branch 1 not taken.
|
666740 | auto shard = ut::new_withkey<Fil_shard>(UT_NEW_THIS_FILE_PSI_KEY, i); |
| 2013 | |||
| 2014 |
1/2✓ Branch 0 taken 666740 times.
✗ Branch 1 not taken.
|
666740 | m_shards.push_back(shard); |
| 2015 | } | ||
| 2016 | 9805 | } | |
| 2017 | |||
| 2018 | /** Destructor */ | ||
| 2019 | 8379 | Fil_system::~Fil_system() { | |
| 2020 |
2/2✓ Branch 0 taken 569772 times.
✓ Branch 1 taken 8379 times.
|
578151 | for (auto shard : m_shards) { |
| 2021 | 569772 | ut::delete_(shard); | |
| 2022 | } | ||
| 2023 | |||
| 2024 | 8379 | m_shards.clear(); | |
| 2025 | 8379 | } | |
| 2026 | |||
| 2027 | /** Determines if a file belongs to the least-recently-used list. | ||
| 2028 | @param[in] space Tablespace to check | ||
| 2029 | @return true if the file belongs to fil_system->m_LRU mutex. */ | ||
| 2030 | 336418698 | bool Fil_system::space_belongs_in_LRU(const fil_space_t *space) { | |
| 2031 |
2/3✓ Branch 0 taken 239563475 times.
✓ Branch 1 taken 96859131 times.
✗ Branch 2 not taken.
|
336418698 | switch (space->purpose) { |
| 2032 | 239563475 | case FIL_TYPE_TABLESPACE: | |
| 2033 |
2/2✓ Branch 0 taken 237305187 times.
✓ Branch 1 taken 2258490 times.
|
476875211 | return !fsp_is_system_tablespace(space->id) && |
| 2034 |
2/2✓ Branch 0 taken 163406099 times.
✓ Branch 1 taken 73905637 times.
|
476875413 | !fsp_is_undo_tablespace(space->id); |
| 2035 | |||
| 2036 | 96859131 | case FIL_TYPE_TEMPORARY: | |
| 2037 | case FIL_TYPE_IMPORT: | ||
| 2038 | 96859131 | return true; | |
| 2039 | } | ||
| 2040 | |||
| 2041 | ✗ | ut_d(ut_error); | |
| 2042 | ut_o(return false); | ||
| 2043 | } | ||
| 2044 | |||
| 2045 | /** Constructor | ||
| 2046 | @param[in] shard_id Shard ID */ | ||
| 2047 | 666740 | Fil_shard::Fil_shard(size_t shard_id) | |
| 2048 | 666740 | : m_id(shard_id), | |
| 2049 | 666740 | m_spaces(), | |
| 2050 | 666740 | m_names(), | |
| 2051 | 666740 | m_LRU(), | |
| 2052 | 666740 | m_unflushed_spaces(), | |
| 2053 | 666740 | m_modification_counter(), | |
| 2054 | 666740 | m_space_list(), | |
| 2055 |
2/4✓ Branch 0 taken 666740 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 666740 times.
✗ Branch 3 not taken.
|
2000220 | m_rotation_list() { |
| 2056 |
1/2✓ Branch 0 taken 666740 times.
✗ Branch 1 not taken.
|
666740 | mutex_create(LATCH_ID_FIL_SHARD, &m_mutex); |
| 2057 | 666740 | } | |
| 2058 | |||
| 2059 | /** Map the space ID and name to the tablespace instance. | ||
| 2060 | @param[in] space Tablespace instance */ | ||
| 2061 | 393130 | void Fil_shard::space_add(fil_space_t *space, fil_encryption_t mode) { | |
| 2062 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 393130 times.
|
393130 | ut_ad(mutex_owned()); |
| 2063 | |||
| 2064 | { | ||
| 2065 |
1/2✓ Branch 0 taken 393130 times.
✗ Branch 1 not taken.
|
393130 | auto it = m_spaces.insert(Spaces::value_type(space->id, space)); |
| 2066 | |||
| 2067 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 393130 times.
|
393130 | ut_a(it.second); |
| 2068 | } | ||
| 2069 | |||
| 2070 | { | ||
| 2071 | 393130 | auto name = space->name; | |
| 2072 | |||
| 2073 |
1/2✓ Branch 0 taken 393130 times.
✗ Branch 1 not taken.
|
393130 | auto it = m_names.insert(Names::value_type(name, space)); |
| 2074 | |||
| 2075 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 393130 times.
|
393130 | ut_a(it.second); |
| 2076 | } | ||
| 2077 | |||
| 2078 | 393130 | UT_LIST_ADD_LAST(m_space_list, space); | |
| 2079 | |||
| 2080 | /* Inform key rotation that there could be something | ||
| 2081 | to do */ | ||
| 2082 |
3/4✓ Branch 0 taken 286267 times.
✓ Branch 1 taken 106863 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 286267 times.
|
393130 | if (space->purpose == FIL_TYPE_TABLESPACE && !srv_fil_crypt_rotate_key_age && |
| 2083 | ✗ | fil_crypt_threads_event && | |
| 2084 | ✗ | (mode == FIL_ENCRYPTION_ON || | |
| 2085 | ✗ | (mode == FIL_ENCRYPTION_DEFAULT && | |
| 2086 | ✗ | srv_default_table_encryption == DEFAULT_TABLE_ENC_ONLINE_TO_KEYRING))) { | |
| 2087 | /* Key rotation is not enabled, need to inform background | ||
| 2088 | encryption threads. */ | ||
| 2089 | ✗ | UT_LIST_ADD_LAST(m_rotation_list, space); | |
| 2090 | ✗ | space->is_in_rotation_list = true; | |
| 2091 | ✗ | mutex_enter(&fil_crypt_threads_mutex); | |
| 2092 | ✗ | os_event_set(fil_crypt_threads_event); | |
| 2093 | ✗ | mutex_exit(&fil_crypt_threads_mutex); | |
| 2094 | } | ||
| 2095 | 393130 | } | |
| 2096 | |||
| 2097 | 57259960 | void Fil_shard::add_to_lru_if_needed(fil_node_t *file) { | |
| 2098 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 57260033 times.
|
57259960 | ut_ad(mutex_owned()); |
| 2099 | |||
| 2100 |
2/2✓ Branch 0 taken 19210706 times.
✓ Branch 1 taken 38049299 times.
|
57260033 | if (Fil_system::space_belongs_in_LRU(file->space)) { |
| 2101 | 19210706 | UT_LIST_ADD_FIRST(m_LRU, file); | |
| 2102 | } | ||
| 2103 | 57260059 | } | |
| 2104 | |||
| 2105 | /** Remove the file node from the LRU list. | ||
| 2106 | @param[in,out] file File for the tablespace */ | ||
| 2107 | 57235889 | void Fil_shard::remove_from_LRU(fil_node_t *file) { | |
| 2108 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 57236581 times.
|
57235889 | ut_ad(mutex_owned()); |
| 2109 | |||
| 2110 |
2/2✓ Branch 0 taken 19191724 times.
✓ Branch 1 taken 38044268 times.
|
57236581 | if (Fil_system::space_belongs_in_LRU(file->space)) { |
| 2111 | /* The file is in the LRU list, remove it */ | ||
| 2112 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19191723 times.
|
19191724 | ut_ad(ut_list_exists(m_LRU, file)); |
| 2113 | 19191723 | UT_LIST_REMOVE(m_LRU, file); | |
| 2114 | } | ||
| 2115 | 57236039 | } | |
| 2116 | |||
| 2117 | /** Close a tablespace file based on tablespace ID. | ||
| 2118 | @param[in] space_id Tablespace ID | ||
| 2119 | @return false if space_id was not found. */ | ||
| 2120 | 170096 | bool Fil_shard::close_file(space_id_t space_id) { | |
| 2121 | 170096 | mutex_acquire(); | |
| 2122 | |||
| 2123 | 170096 | auto space = get_space_by_id(space_id); | |
| 2124 | |||
| 2125 |
2/2✓ Branch 0 taken 83197 times.
✓ Branch 1 taken 86899 times.
|
170096 | if (space == nullptr) { |
| 2126 | 83197 | mutex_release(); | |
| 2127 | |||
| 2128 | 83197 | return false; | |
| 2129 | } | ||
| 2130 | |||
| 2131 |
2/2✓ Branch 0 taken 86899 times.
✓ Branch 1 taken 86899 times.
|
173798 | for (auto &file : space->files) { |
| 2132 |
5/8✓ Branch 0 taken 86443 times.
✓ Branch 1 taken 456 times.
✓ Branch 2 taken 86443 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 86443 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 86899 times.
|
86899 | while (file.is_open && !file.can_be_closed()) { |
| 2133 | ✗ | mutex_release(); | |
| 2134 | |||
| 2135 | ✗ | std::this_thread::sleep_for(std::chrono::milliseconds(10)); | |
| 2136 | |||
| 2137 | ✗ | mutex_acquire(); | |
| 2138 | } | ||
| 2139 | |||
| 2140 |
2/2✓ Branch 0 taken 86443 times.
✓ Branch 1 taken 456 times.
|
86899 | if (file.is_open) { |
| 2141 |
1/2✓ Branch 0 taken 86443 times.
✗ Branch 1 not taken.
|
86443 | close_file(&file); |
| 2142 | } | ||
| 2143 | } | ||
| 2144 | |||
| 2145 | 86899 | mutex_release(); | |
| 2146 | |||
| 2147 | 86899 | return true; | |
| 2148 | } | ||
| 2149 | |||
| 2150 | /** Remap the tablespace to the new name. | ||
| 2151 | @param[in] space Tablespace instance, with old name. | ||
| 2152 | @param[in] new_name New tablespace name */ | ||
| 2153 | 80214 | void Fil_shard::update_space_name_map(fil_space_t *space, | |
| 2154 | const char *new_name) { | ||
| 2155 |
2/4✓ Branch 0 taken 80214 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 80214 times.
|
80214 | ut_ad(mutex_owned()); |
| 2156 | |||
| 2157 |
2/4✓ Branch 0 taken 80214 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 80214 times.
|
80214 | ut_ad(m_spaces.find(space->id) != m_spaces.end()); |
| 2158 | |||
| 2159 |
1/2✓ Branch 0 taken 80214 times.
✗ Branch 1 not taken.
|
80214 | m_names.erase(space->name); |
| 2160 | |||
| 2161 |
1/2✓ Branch 0 taken 80214 times.
✗ Branch 1 not taken.
|
80214 | auto it = m_names.insert(Names::value_type(new_name, space)); |
| 2162 | |||
| 2163 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 80214 times.
|
80214 | ut_a(it.second); |
| 2164 | 80214 | } | |
| 2165 | |||
| 2166 | /** Check if the basename of a filepath is an undo tablespace name | ||
| 2167 | @param[in] name Tablespace name | ||
| 2168 | @return true if it is an undo tablespace name */ | ||
| 2169 | 1835234 | bool Fil_path::is_undo_tablespace_name(const std::string &name) { | |
| 2170 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1835234 times.
|
1835234 | if (name.empty()) { |
| 2171 | ✗ | return false; | |
| 2172 | } | ||
| 2173 | |||
| 2174 |
1/2✓ Branch 0 taken 1835234 times.
✗ Branch 1 not taken.
|
1835234 | std::string basename = Fil_path::get_basename(name); |
| 2175 | |||
| 2176 | 1835234 | const auto end = basename.end(); | |
| 2177 | |||
| 2178 | /* 5 is the minimum length for an explicit undo space name. | ||
| 2179 | It must be at least this long; "_.ibu". */ | ||
| 2180 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1835234 times.
|
1835234 | if (basename.length() <= strlen(DOT_IBU)) { |
| 2181 | ✗ | return false; | |
| 2182 | } | ||
| 2183 | |||
| 2184 | /* Implicit undo names can come in two formats: undo_000 and undo000. | ||
| 2185 | Check for both. */ | ||
| 2186 |
2/2✓ Branch 0 taken 289878 times.
✓ Branch 1 taken 1545356 times.
|
1835234 | size_t u = (*(end - 4) == '_') ? 1 : 0; |
| 2187 | |||
| 2188 | 1835234 | if (basename.length() == sizeof("undo000") - 1 + u && | |
| 2189 |
2/2✓ Branch 0 taken 18772 times.
✓ Branch 1 taken 9802 times.
|
28574 | *(end - 7 - u) == 'u' && /* 'u' */ |
| 2190 |
1/2✓ Branch 0 taken 18772 times.
✗ Branch 1 not taken.
|
18772 | *(end - 6 - u) == 'n' && /* 'n' */ |
| 2191 |
1/2✓ Branch 0 taken 18772 times.
✗ Branch 1 not taken.
|
18772 | *(end - 5 - u) == 'd' && /* 'd' */ |
| 2192 |
1/2✓ Branch 0 taken 18772 times.
✗ Branch 1 not taken.
|
18772 | *(end - 4 - u) == 'o' && /* 'o' */ |
| 2193 |
1/2✓ Branch 0 taken 18772 times.
✗ Branch 1 not taken.
|
18772 | isdigit(*(end - 3)) && /* 'n' */ |
| 2194 |
3/4✓ Branch 0 taken 28574 times.
✓ Branch 1 taken 1806660 times.
✓ Branch 2 taken 18772 times.
✗ Branch 3 not taken.
|
1882580 | isdigit(*(end - 2)) && /* 'n' */ |
| 2195 |
3/4✓ Branch 0 taken 18772 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18772 times.
✓ Branch 3 taken 1816462 times.
|
1854006 | isdigit(*(end - 1))) { /* 'n' */ |
| 2196 | 18772 | return true; | |
| 2197 | } | ||
| 2198 | |||
| 2199 |
3/4✓ Branch 0 taken 1816462 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 264 times.
✓ Branch 3 taken 1816198 times.
|
1816462 | if (basename.substr(basename.length() - 4, 4) == DOT_IBU) { |
| 2200 | 264 | return true; | |
| 2201 | } | ||
| 2202 | |||
| 2203 | 1816198 | return false; | |
| 2204 | 1835234 | } | |
| 2205 | |||
| 2206 | /** Add a space ID to filename mapping. | ||
| 2207 | @param[in] space_id Tablespace ID | ||
| 2208 | @param[in] name File name. | ||
| 2209 | @return number of files that map to the space ID */ | ||
| 2210 | 78701 | size_t Tablespace_files::add(space_id_t space_id, const std::string &name) { | |
| 2211 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78701 times.
|
78701 | ut_a(space_id != TRX_SYS_SPACE); |
| 2212 | |||
| 2213 | Names *names; | ||
| 2214 | |||
| 2215 |
2/2✓ Branch 0 taken 19030 times.
✓ Branch 1 taken 59671 times.
|
78701 | if (undo::is_reserved(space_id)) { |
| 2216 |
3/6✓ Branch 0 taken 19030 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19030 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19030 times.
|
19030 | ut_ad(!Fil_path::has_suffix(IBD, name.c_str())); |
| 2217 | |||
| 2218 | /* Use m_undo_nums to allow a reserved undo space ID | ||
| 2219 | to be found quickly. */ | ||
| 2220 | 19030 | space_id_t space_num = undo::id2num(space_id); | |
| 2221 |
1/2✓ Branch 0 taken 19030 times.
✗ Branch 1 not taken.
|
19030 | m_undo_nums[space_num] = space_id; |
| 2222 | |||
| 2223 |
1/2✓ Branch 0 taken 19030 times.
✗ Branch 1 not taken.
|
19030 | names = &m_undo_paths[space_id]; |
| 2224 | |||
| 2225 | } else { | ||
| 2226 |
3/6✓ Branch 0 taken 59671 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 59671 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 59671 times.
|
59671 | ut_ad(!Fil_path::has_suffix(IBU, name.c_str())); |
| 2227 | |||
| 2228 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 59671 times.
|
59671 | if (0 == strncmp(name.c_str(), "undo_", 5)) { |
| 2229 | ✗ | ib::warn(ER_IB_MSG_267) << "Tablespace '" << name << "' naming" | |
| 2230 | ✗ | << " format is like an undo tablespace" | |
| 2231 | ✗ | << " but its ID " << space_id << " is not" | |
| 2232 | ✗ | << " in the undo tablespace range"; | |
| 2233 | } | ||
| 2234 | |||
| 2235 | 59671 | names = &m_ibd_paths[space_id]; | |
| 2236 | } | ||
| 2237 | |||
| 2238 | 78701 | names->push_back(name); | |
| 2239 | |||
| 2240 | 78701 | return names->size(); | |
| 2241 | } | ||
| 2242 | |||
| 2243 | /** Reads data from a space to a buffer. Remember that the possible incomplete | ||
| 2244 | blocks at the end of file are ignored: they are not taken into account when | ||
| 2245 | calculating the byte offset within a space. | ||
| 2246 | @param[in] page_id page id | ||
| 2247 | @param[in] page_size page size | ||
| 2248 | @param[in] byte_offset remainder of offset in bytes; in aio this | ||
| 2249 | must be divisible by the OS block size | ||
| 2250 | @param[in] len how many bytes to read; this must not cross a | ||
| 2251 | file boundary; in aio this must be a block size multiple | ||
| 2252 | @param[in,out] buf buffer where to store data read; in aio this | ||
| 2253 | must be appropriately aligned | ||
| 2254 | @return DB_SUCCESS, or DB_TABLESPACE_DELETED if we are trying to do | ||
| 2255 | i/o on a tablespace which does not exist */ | ||
| 2256 | 8663 | static dberr_t fil_read(const page_id_t &page_id, const page_size_t &page_size, | |
| 2257 | ulint byte_offset, ulint len, void *buf) { | ||
| 2258 |
1/2✓ Branch 0 taken 8663 times.
✗ Branch 1 not taken.
|
8663 | return fil_io(IORequestRead, true, page_id, page_size, byte_offset, len, buf, |
| 2259 | nullptr); | ||
| 2260 | } | ||
| 2261 | |||
| 2262 | /** Writes data to a space from a buffer. Remember that the possible incomplete | ||
| 2263 | blocks at the end of file are ignored: they are not taken into account when | ||
| 2264 | calculating the byte offset within a space. | ||
| 2265 | @param[in] page_id page id | ||
| 2266 | @param[in] page_size page size | ||
| 2267 | @param[in] byte_offset remainder of offset in bytes; in aio this | ||
| 2268 | must be divisible by the OS block size | ||
| 2269 | @param[in] len how many bytes to write; this must not cross | ||
| 2270 | a file boundary; in aio this must be a block size multiple | ||
| 2271 | @param[in] buf buffer from which to write; in aio this must | ||
| 2272 | be appropriately aligned | ||
| 2273 | @return DB_SUCCESS, or DB_TABLESPACE_DELETED if we are trying to do | ||
| 2274 | I/O on a tablespace which does not exist */ | ||
| 2275 | 8663 | static dberr_t fil_write(const page_id_t &page_id, const page_size_t &page_size, | |
| 2276 | ulint byte_offset, ulint len, void *buf) { | ||
| 2277 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8663 times.
|
8663 | ut_ad(!srv_read_only_mode); |
| 2278 | |||
| 2279 |
1/2✓ Branch 0 taken 8663 times.
✗ Branch 1 not taken.
|
8663 | return fil_io(IORequestWrite, true, page_id, page_size, byte_offset, len, buf, |
| 2280 | nullptr); | ||
| 2281 | } | ||
| 2282 | |||
| 2283 | /** Look up a tablespace. The caller should hold an InnoDB table lock or | ||
| 2284 | a MDL that prevents the tablespace from being dropped during the operation, | ||
| 2285 | or the caller should be in single-threaded crash recovery mode (no user | ||
| 2286 | connections that could drop tablespaces). If this is not the case, | ||
| 2287 | fil_space_acquire() and fil_space_release() should be used instead. | ||
| 2288 | @param[in] space_id Tablespace ID | ||
| 2289 | @return tablespace, or nullptr if not found */ | ||
| 2290 | 148871583 | fil_space_t *fil_space_get(space_id_t space_id) { | |
| 2291 | 148871583 | auto shard = fil_system->shard_by_id(space_id); | |
| 2292 | |||
| 2293 | 148871772 | shard->mutex_acquire(); | |
| 2294 | |||
| 2295 | 148871732 | fil_space_t *space = shard->get_space_by_id(space_id); | |
| 2296 | |||
| 2297 | 148871549 | shard->mutex_release(); | |
| 2298 | |||
| 2299 | 148871906 | return space; | |
| 2300 | } | ||
| 2301 | |||
| 2302 | #ifndef UNIV_HOTBACKUP | ||
| 2303 | |||
| 2304 | /** Returns the latch of a file space. | ||
| 2305 | @param[in] space_id Tablespace ID | ||
| 2306 | @return latch protecting storage allocation */ | ||
| 2307 | 4280863 | rw_lock_t *fil_space_get_latch(space_id_t space_id) { | |
| 2308 | 4280863 | auto shard = fil_system->shard_by_id(space_id); | |
| 2309 | |||
| 2310 | 4280862 | shard->mutex_acquire(); | |
| 2311 | |||
| 2312 | 4280862 | fil_space_t *space = shard->get_space_by_id(space_id); | |
| 2313 | |||
| 2314 | 4280862 | shard->mutex_release(); | |
| 2315 | |||
| 2316 | 4280863 | return &space->latch; | |
| 2317 | } | ||
| 2318 | |||
| 2319 | #ifdef UNIV_DEBUG | ||
| 2320 | |||
| 2321 | /** Gets the type of a file space. | ||
| 2322 | @param[in] space_id Tablespace ID | ||
| 2323 | @return file type */ | ||
| 2324 | 20316404 | fil_type_t fil_space_get_type(space_id_t space_id) { | |
| 2325 | 20316404 | auto shard = fil_system->shard_by_id(space_id); | |
| 2326 | |||
| 2327 | 20316403 | shard->mutex_acquire(); | |
| 2328 | |||
| 2329 | 20316400 | auto space = shard->get_space_by_id(space_id); | |
| 2330 | |||
| 2331 | 20316399 | shard->mutex_release(); | |
| 2332 | |||
| 2333 | 20316404 | return space->purpose; | |
| 2334 | } | ||
| 2335 | |||
| 2336 | #endif /* UNIV_DEBUG */ | ||
| 2337 | |||
| 2338 | 524 | void fil_space_set_imported(space_id_t space_id) { | |
| 2339 | 524 | auto shard = fil_system->shard_by_id(space_id); | |
| 2340 | |||
| 2341 | 524 | shard->mutex_acquire(); | |
| 2342 | |||
| 2343 | 524 | fil_space_t *space = shard->get_space_by_id(space_id); | |
| 2344 | |||
| 2345 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 524 times.
|
524 | ut_ad(space->purpose == FIL_TYPE_IMPORT); |
| 2346 | 524 | space->purpose = FIL_TYPE_TABLESPACE; | |
| 2347 | |||
| 2348 | 524 | shard->mutex_release(); | |
| 2349 | 524 | } | |
| 2350 | #endif /* !UNIV_HOTBACKUP */ | ||
| 2351 | |||
| 2352 | /** Checks if all the file nodes in a space are flushed. The caller must hold | ||
| 2353 | the fil_system mutex. | ||
| 2354 | @param[in] space Tablespace to check | ||
| 2355 | @return true if all are flushed */ | ||
| 2356 | 8550206 | bool Fil_shard::space_is_flushed(const fil_space_t *space) { | |
| 2357 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8551162 times.
|
8550206 | ut_ad(mutex_owned()); |
| 2358 | |||
| 2359 |
2/2✓ Branch 0 taken 8551345 times.
✓ Branch 1 taken 7557517 times.
|
16111296 | for (const auto &file : space->files) { |
| 2360 |
3/4✓ Branch 0 taken 8553895 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 993761 times.
✓ Branch 3 taken 7560134 times.
|
8551647 | if (!file.is_flushed()) { |
| 2361 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 993756 times.
|
993761 | ut_ad(!fil_disable_space_flushing(space)); |
| 2362 | 993756 | return false; | |
| 2363 | } | ||
| 2364 | } | ||
| 2365 | |||
| 2366 | 7557517 | return true; | |
| 2367 | } | ||
| 2368 | |||
| 2369 | #if !defined(NO_FALLOCATE) && defined(UNIV_LINUX) | ||
| 2370 | |||
| 2371 | #include <sys/ioctl.h> | ||
| 2372 | |||
| 2373 | /** FusionIO atomic write control info */ | ||
| 2374 | #define DFS_IOCTL_ATOMIC_WRITE_SET _IOW(0x95, 2, uint) | ||
| 2375 | |||
| 2376 | /** Try and enable FusionIO atomic writes. | ||
| 2377 | @param[in] file OS file handle | ||
| 2378 | @return true if successful */ | ||
| 2379 | 217839 | bool fil_fusionio_enable_atomic_write(pfs_os_file_t file) { | |
| 2380 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 217811 times.
|
217839 | if (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) { |
| 2381 | 28 | uint atomic = 1; | |
| 2382 | |||
| 2383 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | ut_a(file.m_file != -1); |
| 2384 | |||
| 2385 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | if (ioctl(file.m_file, DFS_IOCTL_ATOMIC_WRITE_SET, &atomic) != -1) { |
| 2386 | ✗ | return true; | |
| 2387 | } | ||
| 2388 | } | ||
| 2389 | |||
| 2390 | 217839 | return false; | |
| 2391 | } | ||
| 2392 | #endif /* !NO_FALLOCATE && UNIV_LINUX */ | ||
| 2393 | |||
| 2394 | /** Attach a file to a tablespace | ||
| 2395 | @param[in] name file name of a file that is not open | ||
| 2396 | @param[in] size file size in entire database blocks | ||
| 2397 | @param[in,out] space tablespace from fil_space_create() | ||
| 2398 | @param[in] is_raw whether this is a raw device or partition | ||
| 2399 | @param[in] punch_hole true if supported for this file | ||
| 2400 | @param[in] atomic_write true if the file has atomic write enabled | ||
| 2401 | @param[in] max_pages maximum number of pages in file | ||
| 2402 | @return pointer to the file name | ||
| 2403 | @retval nullptr if error */ | ||
| 2404 | 393161 | fil_node_t *Fil_shard::create_node(const char *name, page_no_t size, | |
| 2405 | fil_space_t *space, bool is_raw, | ||
| 2406 | bool punch_hole, bool atomic_write, | ||
| 2407 | page_no_t max_pages) { | ||
| 2408 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 393161 times.
|
393161 | ut_ad(name != nullptr); |
| 2409 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 393161 times.
|
393161 | ut_ad(fil_system != nullptr); |
| 2410 | |||
| 2411 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 393161 times.
|
393161 | if (space == nullptr) { |
| 2412 | ✗ | return nullptr; | |
| 2413 | } | ||
| 2414 | |||
| 2415 | 393161 | fil_node_t file{}; | |
| 2416 | |||
| 2417 |
1/2✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
|
393161 | file.name = mem_strdup(name); |
| 2418 | |||
| 2419 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 393161 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 393161 times.
|
393161 | ut_a(!is_raw || srv_start_raw_disk_in_use); |
| 2420 | |||
| 2421 |
1/2✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
|
393161 | file.sync_event = os_event_create(); |
| 2422 | |||
| 2423 | 393161 | file.is_raw_disk = is_raw; | |
| 2424 | |||
| 2425 | 393161 | file.size = size; | |
| 2426 | |||
| 2427 | 393161 | file.flush_size = size; | |
| 2428 | |||
| 2429 | 393161 | file.magic_n = FIL_NODE_MAGIC_N; | |
| 2430 | |||
| 2431 | 393161 | file.init_size = size; | |
| 2432 | |||
| 2433 | 393161 | file.max_size = max_pages; | |
| 2434 | |||
| 2435 | 393161 | file.space = space; | |
| 2436 | |||
| 2437 | 393161 | os_file_stat_t stat_info = os_file_stat_t(); | |
| 2438 | |||
| 2439 | #ifdef UNIV_DEBUG | ||
| 2440 | dberr_t err = | ||
| 2441 | #endif /* UNIV_DEBUG */ | ||
| 2442 | |||
| 2443 | 393161 | os_file_get_status( | |
| 2444 |
1/2✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
|
393161 | file.name, &stat_info, false, |
| 2445 |
3/4✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 106324 times.
✓ Branch 3 taken 286837 times.
|
393161 | fsp_is_system_temporary(space->id) ? true : srv_read_only_mode); |
| 2446 | |||
| 2447 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 393161 times.
|
393161 | ut_ad(err == DB_SUCCESS); |
| 2448 | |||
| 2449 | 393161 | file.block_size = stat_info.block_size; | |
| 2450 | |||
| 2451 | /* In this debugging mode, we can overcome the limitation of some | ||
| 2452 | OSes like Windows that support Punch Hole but have a hole size | ||
| 2453 | effectively too large. By setting the block size to be half the | ||
| 2454 | page size, we can bypass one of the checks that would normally | ||
| 2455 | turn Page Compression off. This execution mode allows compression | ||
| 2456 | to be tested even when full punch hole support is not available. */ | ||
| 2457 |
3/4✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 393145 times.
|
393161 | DBUG_EXECUTE_IF( |
| 2458 | "ignore_punch_hole", | ||
| 2459 | file.block_size = std::min(static_cast<ulint>(stat_info.block_size), | ||
| 2460 | UNIV_PAGE_SIZE / 2);); | ||
| 2461 | |||
| 2462 |
6/8✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 393161 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 391914 times.
✓ Branch 5 taken 1247 times.
✓ Branch 6 taken 1247 times.
✓ Branch 7 taken 391914 times.
|
785075 | if (!IORequest::is_punch_hole_supported() || !punch_hole || |
| 2463 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 391914 times.
|
391914 | file.block_size >= srv_page_size) { |
| 2464 |
1/2✓ Branch 0 taken 1247 times.
✗ Branch 1 not taken.
|
1247 | fil_no_punch_hole(&file); |
| 2465 | } else { | ||
| 2466 | 391914 | file.punch_hole = punch_hole; | |
| 2467 | } | ||
| 2468 | |||
| 2469 | 393161 | file.atomic_write = atomic_write; | |
| 2470 | |||
| 2471 |
1/2✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
|
393161 | mutex_acquire(); |
| 2472 | |||
| 2473 | 393161 | space->size += size; | |
| 2474 | |||
| 2475 |
1/2✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
|
393161 | space->files.push_back(file); |
| 2476 | |||
| 2477 |
1/2✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
|
393161 | mutex_release(); |
| 2478 | |||
| 2479 |
6/8✓ Branch 0 taken 383444 times.
✓ Branch 1 taken 9717 times.
✓ Branch 2 taken 277120 times.
✓ Branch 3 taken 106324 times.
✓ Branch 4 taken 277120 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 393161 times.
|
393161 | ut_a(space->id == TRX_SYS_SPACE || space->purpose == FIL_TYPE_TEMPORARY || |
| 2480 | space->files.size() == 1); | ||
| 2481 | |||
| 2482 | 393161 | return &space->files.front(); | |
| 2483 | } | ||
| 2484 | |||
| 2485 | /** Attach a file to a tablespace. File must be closed. | ||
| 2486 | @param[in] name file name (file must be closed) | ||
| 2487 | @param[in] size file size in database blocks, rounded | ||
| 2488 | downwards to an integer | ||
| 2489 | @param[in,out] space space where to append | ||
| 2490 | @param[in] is_raw true if a raw device or a raw disk partition | ||
| 2491 | @param[in] atomic_write true if the file has atomic write enabled | ||
| 2492 | @param[in] max_pages maximum number of pages in file | ||
| 2493 | @return pointer to the file name | ||
| 2494 | @retval nullptr if error */ | ||
| 2495 | 35629 | char *fil_node_create(const char *name, page_no_t size, fil_space_t *space, | |
| 2496 | bool is_raw, bool atomic_write, page_no_t max_pages) { | ||
| 2497 | 35629 | auto shard = fil_system->shard_by_id(space->id); | |
| 2498 | |||
| 2499 | fil_node_t *file; | ||
| 2500 | |||
| 2501 | 106887 | file = shard->create_node(name, size, space, is_raw, | |
| 2502 | 35629 | IORequest::is_punch_hole_supported(), atomic_write, | |
| 2503 | max_pages); | ||
| 2504 | |||
| 2505 |
1/2✓ Branch 0 taken 35629 times.
✗ Branch 1 not taken.
|
35629 | return file == nullptr ? nullptr : file->name; |
| 2506 | } | ||
| 2507 | |||
| 2508 | 59268 | dberr_t Fil_shard::get_file_size(fil_node_t *file, bool read_only_mode) { | |
| 2509 |
2/4✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 59268 times.
|
59268 | ut_ad(mutex_owned()); |
| 2510 | |||
| 2511 | bool success; | ||
| 2512 | 59268 | fil_space_t *space = file->space; | |
| 2513 |
2/4✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 59268 times.
|
59268 | ut_ad(mutex_owned()); |
| 2514 | |||
| 2515 | do { | ||
| 2516 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
|
59270 | ut_a(!file->is_open); |
| 2517 | |||
| 2518 |
1/2✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
|
59268 | file->handle = os_file_create_simple_no_error_handling( |
| 2519 | innodb_data_file_key, file->name, OS_FILE_OPEN, OS_FILE_READ_ONLY, | ||
| 2520 | read_only_mode, &success); | ||
| 2521 | |||
| 2522 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
|
59268 | if (!success) { |
| 2523 | /* The following call prints an error message */ | ||
| 2524 | ✗ | os_file_get_last_error(true); | |
| 2525 | |||
| 2526 | ✗ | ib::warn(ER_IB_MSG_268) << "Cannot open '" << file->name | |
| 2527 | << "'." | ||
| 2528 | " Have you deleted .ibd files under a" | ||
| 2529 | ✗ | " running mysqld server?"; | |
| 2530 | |||
| 2531 | ✗ | return DB_ERROR; | |
| 2532 | } | ||
| 2533 | |||
| 2534 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 59266 times.
|
59268 | } while (!success); |
| 2535 | |||
| 2536 |
1/2✓ Branch 0 taken 59266 times.
✗ Branch 1 not taken.
|
59266 | os_offset_t size_bytes = os_file_get_size(file->handle); |
| 2537 | |||
| 2538 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 59266 times.
|
59266 | ut_a(size_bytes != (os_offset_t)-1); |
| 2539 | |||
| 2540 | #ifdef UNIV_HOTBACKUP | ||
| 2541 | if (space->id == TRX_SYS_SPACE) { | ||
| 2542 | file->size = (ulint)(size_bytes / UNIV_PAGE_SIZE); | ||
| 2543 | space->size += file->size; | ||
| 2544 | os_file_close(file->handle); | ||
| 2545 | return DB_SUCCESS; | ||
| 2546 | } | ||
| 2547 | #endif /* UNIV_HOTBACKUP */ | ||
| 2548 | |||
| 2549 | /* Align memory for file I/O if we might have O_DIRECT set */ | ||
| 2550 | const ulint buf_size = | ||
| 2551 |
2/2✓ Branch 0 taken 9528 times.
✓ Branch 1 taken 49737 times.
|
59266 | recv_recovery_is_on() ? (UNIV_PAGE_SIZE * 2) : UNIV_PAGE_SIZE; |
| 2552 | 59265 | auto page = static_cast<byte *>(ut::aligned_alloc(buf_size, UNIV_PAGE_SIZE)); | |
| 2553 | |||
| 2554 |
2/4✓ Branch 0 taken 59267 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 59267 times.
|
59268 | ut_ad(page == page_align(page)); |
| 2555 | |||
| 2556 | /* Read the first page of the tablespace */ | ||
| 2557 | |||
| 2558 |
1/2✓ Branch 0 taken 59267 times.
✗ Branch 1 not taken.
|
59267 | IORequest request(IORequest::READ); |
| 2559 | |||
| 2560 |
1/2✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
|
59267 | dberr_t err = os_file_read_first_page(request, file->name, file->handle, page, |
| 2561 | buf_size); | ||
| 2562 | |||
| 2563 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
|
59268 | ut_a(err == DB_SUCCESS); |
| 2564 | |||
| 2565 |
1/2✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
|
59268 | os_file_close(file->handle); |
| 2566 | |||
| 2567 |
1/2✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
|
59268 | uint32_t flags = fsp_header_get_flags(page); |
| 2568 |
1/2✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
|
59268 | space_id_t space_id = fsp_header_get_space_id(page); |
| 2569 | |||
| 2570 | /* To determine if tablespace is from 5.7 or not, we | ||
| 2571 | rely on SDI flag. For IBDs from 5.7, which are opened | ||
| 2572 | during import or during upgrade, their initial size | ||
| 2573 | is lesser than the initial size in 8.0 */ | ||
| 2574 | 59268 | bool has_sdi = FSP_FLAGS_HAS_SDI(flags); | |
| 2575 | |||
| 2576 |
2/2✓ Branch 0 taken 34188 times.
✓ Branch 1 taken 25080 times.
|
59268 | uint8_t expected_size = |
| 2577 | has_sdi ? FIL_IBD_FILE_INITIAL_SIZE : FIL_IBD_FILE_INITIAL_SIZE_5_7; | ||
| 2578 | |||
| 2579 |
1/2✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
|
59268 | const page_size_t page_size(flags); |
| 2580 | |||
| 2581 |
1/2✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
|
59268 | ulint min_size = expected_size * page_size.physical(); |
| 2582 | |||
| 2583 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
|
59268 | if (size_bytes < min_size) { |
| 2584 | ✗ | if (has_sdi) { | |
| 2585 | /** Add some tolerance when the tablespace is upgraded. If an empty | ||
| 2586 | general tablespace is created in 5.7, and then upgraded to 8.0, then | ||
| 2587 | its size changes from FIL_IBD_FILE_INITIAL_SIZE_5_7 pages to | ||
| 2588 | FIL_IBD_FILE_INITIAL_SIZE-1. */ | ||
| 2589 | |||
| 2590 | ✗ | ut_ad(expected_size == FIL_IBD_FILE_INITIAL_SIZE); | |
| 2591 | ✗ | ulint upgrade_size = (expected_size - 1) * page_size.physical(); | |
| 2592 | |||
| 2593 | ✗ | if (size_bytes < upgrade_size) { | |
| 2594 | ✗ | ib::error(ER_IB_MSG_269) | |
| 2595 | ✗ | << "The size of tablespace file " << file->name << " is only " | |
| 2596 | ✗ | << size_bytes << ", should be at least " << upgrade_size << "!"; | |
| 2597 | |||
| 2598 | ✗ | ut_error; | |
| 2599 | } | ||
| 2600 | |||
| 2601 | } else { | ||
| 2602 | ✗ | ib::error(ER_IB_MSG_269) | |
| 2603 | ✗ | << "The size of tablespace file " << file->name << " is only " | |
| 2604 | ✗ | << size_bytes << ", should be at least " << min_size << "!"; | |
| 2605 | |||
| 2606 | ✗ | ut_error; | |
| 2607 | } | ||
| 2608 | } | ||
| 2609 | |||
| 2610 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
|
59268 | if (space_id != space->id) { |
| 2611 | ✗ | ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_270) | |
| 2612 | ✗ | << "Tablespace id is " << space->id | |
| 2613 | ✗ | << " in the data dictionary but in file " << file->name << " it is " | |
| 2614 | ✗ | << space_id << "!"; | |
| 2615 | } | ||
| 2616 | |||
| 2617 | /* We need to adjust for compressed pages. */ | ||
| 2618 |
1/2✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
|
59268 | const page_size_t space_page_size(space->flags); |
| 2619 | |||
| 2620 |
2/4✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 59268 times.
|
59268 | if (!page_size.equals_to(space_page_size)) { |
| 2621 | ✗ | ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_271) | |
| 2622 | ✗ | << "Tablespace file " << file->name << " has page size " << page_size | |
| 2623 | ✗ | << " (flags=" << ib::hex(flags) << ") but the data dictionary expects" | |
| 2624 | ✗ | << " page size " << space_page_size | |
| 2625 | ✗ | << " (flags=" << ib::hex(space->flags) << ")!"; | |
| 2626 | } | ||
| 2627 | |||
| 2628 | /* Make the SDI flag in space->flags reflect the SDI flag in the header | ||
| 2629 | page. Maybe this space was discarded before a reboot and then replaced | ||
| 2630 | with a 5.7 space that needs to be imported and upgraded. */ | ||
| 2631 | 59268 | fsp_flags_unset_sdi(space->flags); | |
| 2632 | 59268 | space->flags |= flags & FSP_FLAGS_MASK_SDI; | |
| 2633 | |||
| 2634 | /* Data dictionary and tablespace are flushed at different points in | ||
| 2635 | time. If a crash happens in between, they can have different | ||
| 2636 | encryption flags as long as the redo log is not replayed. To avoid a | ||
| 2637 | recovery error due to differing encryption flags, ensure that the | ||
| 2638 | fil_space_t instance has the same setting as the header page. First | ||
| 2639 | clear the encryption flag, then set it from the flags found in the | ||
| 2640 | file. | ||
| 2641 | It is also possible that for tables, general tablespaces encryption flag | ||
| 2642 | is updated in DD but server crashed before encryption flag is updated on | ||
| 2643 | disk. | ||
| 2644 | Below we print warning in such case. */ | ||
| 2645 |
6/6✓ Branch 0 taken 59265 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 9525 times.
✓ Branch 3 taken 49740 times.
✓ Branch 4 taken 9525 times.
✓ Branch 5 taken 49743 times.
|
59268 | if (space->crypt_data == nullptr && recv_recovery_is_on()) { |
| 2646 | 9525 | fsp_flags_unset_encryption(space->flags); | |
| 2647 | 9525 | space->flags |= flags & FSP_FLAGS_MASK_ENCRYPTION; | |
| 2648 | } | ||
| 2649 | |||
| 2650 | /* Make a copy of space->flags and flags from the page header | ||
| 2651 | so that they can be compared. */ | ||
| 2652 | /* Do not compare the data directory flag, in case this tablespace was | ||
| 2653 | relocated. */ | ||
| 2654 | 59268 | auto fil_space_flags = space->flags & ~FSP_FLAGS_MASK_DATA_DIR; | |
| 2655 | 59268 | auto header_fsp_flags = flags & ~FSP_FLAGS_MASK_DATA_DIR; | |
| 2656 | |||
| 2657 | // in case of Keyring encryption it can so happen that there will be a crash | ||
| 2658 | // after all pages of tablespace is rotated and DD is updated, but page0 of | ||
| 2659 | // the tablespace has not been yet update. We handle this here. | ||
| 2660 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (space->crypt_data != nullptr && |
| 2661 | 3 | ((FSP_FLAGS_GET_ENCRYPTION(fil_space_flags) && | |
| 2662 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | space->crypt_data->min_key_version == 0) || |
| 2663 | 3 | (!FSP_FLAGS_GET_ENCRYPTION(fil_space_flags) && | |
| 2664 |
4/8✓ Branch 0 taken 3 times.
✓ Branch 1 taken 59265 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 59268 times.
|
59271 | space->crypt_data->min_key_version != 0)) && |
| 2665 | ✗ | FSP_FLAGS_GET_ENCRYPTION(fil_space_flags) != | |
| 2666 | ✗ | FSP_FLAGS_GET_ENCRYPTION(header_fsp_flags)) { | |
| 2667 | ✗ | if (srv_n_fil_crypt_threads_requested == 0) { | |
| 2668 | ✗ | ib::warn() << "Table encryption flag is " | |
| 2669 | ✗ | << (FSP_FLAGS_GET_ENCRYPTION(fil_space_flags) ? "ON" : "OFF") | |
| 2670 | ✗ | << " in the data dictionary but the encryption flag in file " | |
| 2671 | ✗ | << file->name << " is " | |
| 2672 | ✗ | << (FSP_FLAGS_GET_ENCRYPTION(header_fsp_flags) ? "ON" : "OFF") | |
| 2673 | << ". This indicates that the rotation of the table was " | ||
| 2674 | ✗ | "interrupted before space's flags were updated." | |
| 2675 | << " Please have encryption_thread variable " | ||
| 2676 | "(innodb-encryption-threads) set to value > 0. So the " | ||
| 2677 | ✗ | "encryption" | |
| 2678 | ✗ | << " could finish up the rotation."; | |
| 2679 | } | ||
| 2680 | // exclude encryption flag from validation | ||
| 2681 | ✗ | fsp_flags_unset_encryption(fil_space_flags); | |
| 2682 | ✗ | fsp_flags_unset_encryption(header_fsp_flags); | |
| 2683 | } | ||
| 2684 | |||
| 2685 | /* Make sure the space_flags are the same as the header page flags. */ | ||
| 2686 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
|
59268 | if (UNIV_UNLIKELY(fil_space_flags != header_fsp_flags)) { |
| 2687 | ✗ | ib::error(ER_IB_MSG_272, ulong{space->flags}, file->name, ulonglong{flags}); | |
| 2688 | ✗ | ut_error; | |
| 2689 | } | ||
| 2690 | |||
| 2691 | { | ||
| 2692 |
1/2✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
|
59268 | page_no_t size = fsp_header_get_field(page, FSP_SIZE); |
| 2693 | |||
| 2694 | page_no_t free_limit; | ||
| 2695 | |||
| 2696 |
1/2✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
|
59268 | free_limit = fsp_header_get_field(page, FSP_FREE_LIMIT); |
| 2697 | |||
| 2698 | ulint free_len; | ||
| 2699 | |||
| 2700 |
1/2✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
|
59268 | free_len = flst_get_len(FSP_HEADER_OFFSET + FSP_FREE + page); |
| 2701 | |||
| 2702 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 59268 times.
|
59268 | ut_ad(space->free_limit == 0 || space->free_limit == free_limit); |
| 2703 | |||
| 2704 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 59268 times.
|
59268 | ut_ad(space->free_len == 0 || space->free_len == free_len); |
| 2705 | |||
| 2706 | 59268 | space->size_in_header = size; | |
| 2707 | 59268 | space->free_limit = free_limit; | |
| 2708 | |||
| 2709 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
|
59268 | ut_a(free_len < std::numeric_limits<uint32_t>::max()); |
| 2710 | |||
| 2711 | 59268 | space->free_len = (uint32_t)free_len; | |
| 2712 | |||
| 2713 | /* TODO: Get consistent flag from recovered DD. For that, DD should be | ||
| 2714 | recovered already. */ | ||
| 2715 | /* Set estimated value for space->compression_type | ||
| 2716 | during recovery process. */ | ||
| 2717 | |||
| 2718 |
4/4✓ Branch 0 taken 9528 times.
✓ Branch 1 taken 49740 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 59244 times.
|
68796 | if (recv_recovery_is_on() && |
| 2719 |
4/6✓ Branch 0 taken 9528 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9528 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9512 times.
✓ Branch 5 taken 16 times.
|
9528 | (Compression::is_compressed_page(page + page_size.physical()) || |
| 2720 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 9504 times.
|
9512 | Compression::is_compressed_encrypted_page(page + |
| 2721 |
2/4✓ Branch 0 taken 9512 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9512 times.
✗ Branch 3 not taken.
|
9512 | page_size.physical()))) { |
| 2722 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | ut_ad(buf_size >= (UNIV_PAGE_SIZE * 2)); |
| 2723 | Compression::meta_t header; | ||
| 2724 |
2/4✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
|
24 | Compression::deserialize_header(page + page_size.physical(), &header); |
| 2725 | 24 | space->compression_type = header.m_algorithm; | |
| 2726 | } | ||
| 2727 | } | ||
| 2728 | |||
| 2729 | 59268 | ut::aligned_free(page); | |
| 2730 | |||
| 2731 | /* For encrypted tablespace, we need to check the | ||
| 2732 | encryption key and iv(initial vector) is read. */ | ||
| 2733 |
5/6✓ Branch 0 taken 636 times.
✓ Branch 1 taken 58632 times.
✓ Branch 2 taken 424 times.
✓ Branch 3 taken 212 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 59268 times.
|
59692 | if (FSP_FLAGS_GET_ENCRYPTION(space->flags) && !recv_recovery_is_on() && |
| 2734 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 424 times.
|
424 | space->m_encryption_metadata.m_type != Encryption::AES) { |
| 2735 | ✗ | ib::error(ER_IB_MSG_273, file->name); | |
| 2736 | |||
| 2737 | ✗ | return DB_ERROR; | |
| 2738 | } | ||
| 2739 | |||
| 2740 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (space->crypt_data && space->crypt_data->type == CRYPT_SCHEME_1 && |
| 2741 |
3/8✓ Branch 0 taken 3 times.
✓ Branch 1 taken 59265 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 59268 times.
|
59271 | !space->crypt_data->key_found && !recv_recovery_is_on()) { |
| 2742 | ✗ | ib::error() << "There is no key for tablespace " << space->name; | |
| 2743 | ✗ | return (DB_IO_DECRYPT_FAIL); | |
| 2744 | } | ||
| 2745 | |||
| 2746 |
2/2✓ Branch 0 taken 34342 times.
✓ Branch 1 taken 24926 times.
|
59268 | if (file->size == 0) { |
| 2747 | ulint extent_size; | ||
| 2748 | |||
| 2749 |
2/6✓ Branch 0 taken 34342 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34342 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
34342 | extent_size = page_size.physical() * FSP_EXTENT_SIZE; |
| 2750 | |||
| 2751 | #ifndef UNIV_HOTBACKUP | ||
| 2752 | /* Truncate the size to a multiple of extent size. */ | ||
| 2753 |
2/2✓ Branch 0 taken 14208 times.
✓ Branch 1 taken 20134 times.
|
34342 | if (size_bytes >= extent_size) { |
| 2754 | 14208 | size_bytes = ut_2pow_round(size_bytes, extent_size); | |
| 2755 | } | ||
| 2756 | #else /* !UNIV_HOTBACKUP */ | ||
| 2757 | |||
| 2758 | /* After apply-incremental, tablespaces are not | ||
| 2759 | extended to a whole megabyte. Do not cut off | ||
| 2760 | valid data. */ | ||
| 2761 | |||
| 2762 | #endif /* !UNIV_HOTBACKUP */ | ||
| 2763 | |||
| 2764 |
1/2✓ Branch 0 taken 34342 times.
✗ Branch 1 not taken.
|
34342 | file->size = static_cast<page_no_t>(size_bytes / page_size.physical()); |
| 2765 | |||
| 2766 | 34342 | space->size += file->size; | |
| 2767 | } | ||
| 2768 | |||
| 2769 | 59268 | return DB_SUCCESS; | |
| 2770 | 59268 | } | |
| 2771 | |||
| 2772 | 35221 | size_t Fil_system::get_limit_for_non_lru_files(size_t open_files_limit) { | |
| 2773 | /* Leave at least 10% of the limit for the LRU files, to not make system too | ||
| 2774 | inefficient in an edge case there is a lot of non-LRU files causing LRU | ||
| 2775 | ones to be constantly closed and opened. The absolute minimum would be a | ||
| 2776 | single slot for LRU files, but it may be very inefficient. Let's make two the | ||
| 2777 | hard limit. */ | ||
| 2778 | const size_t minimum_limit_left_for_lru_files = | ||
| 2779 | 35221 | std::max(2LL, std::llround(0.1 * open_files_limit)); | |
| 2780 | 35221 | return open_files_limit - minimum_limit_left_for_lru_files; | |
| 2781 | } | ||
| 2782 | |||
| 2783 | 28 | size_t Fil_system::get_minimum_limit_for_open_files( | |
| 2784 | size_t n_files_not_belonging_in_lru) const { | ||
| 2785 | 28 | size_t result = 0; | |
| 2786 | /* Start with the most significant bit and iterate till last one. */ | ||
| 2787 | 28 | for (size_t current_bit = ~(std::numeric_limits<size_t>::max() >> 1); | |
| 2788 |
2/2✓ Branch 0 taken 1792 times.
✓ Branch 1 taken 28 times.
|
1820 | current_bit; current_bit >>= 1) { |
| 2789 |
2/2✓ Branch 0 taken 88 times.
✓ Branch 1 taken 1704 times.
|
1792 | if (get_limit_for_non_lru_files(result + current_bit - 1) < |
| 2790 | n_files_not_belonging_in_lru) { | ||
| 2791 | 88 | result += current_bit; | |
| 2792 | } | ||
| 2793 | } | ||
| 2794 | |||
| 2795 | 28 | return result; | |
| 2796 | } | ||
| 2797 | |||
| 2798 | 306702 | bool Fil_shard::open_file(fil_node_t *file) { | |
| 2799 | bool success; | ||
| 2800 | 306702 | fil_space_t *space = file->space; | |
| 2801 | |||
| 2802 |
2/4✓ Branch 0 taken 306704 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 306704 times.
|
306702 | ut_ad(mutex_owned()); |
| 2803 | |||
| 2804 | /* This method is not straightforward. The description is included in comments | ||
| 2805 | to different parts of this function. They are best read one after another | ||
| 2806 | in order. */ | ||
| 2807 | |||
| 2808 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 306703 times.
|
306704 | ut_a(!file->is_open); |
| 2809 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 306703 times.
|
306703 | ut_a(file->n_pending_ios == 0); |
| 2810 | |||
| 2811 | 306703 | const auto start_time = std::chrono::steady_clock::now(); | |
| 2812 | |||
| 2813 | /* This method first assures we can open a file. This comes down to assuring a | ||
| 2814 | correct state under locks is present and that opening of this file will not | ||
| 2815 | exceed any limits. Currently we have two limits for open files: | ||
| 2816 | - maximum number of opened files - fil_system->m_open_files_limit, | ||
| 2817 | - maximum number of opened files that can't be closed on request, i.e. are not | ||
| 2818 | part of open files LRU list. | ||
| 2819 | |||
| 2820 | We can ignore the latter iff the file will be part of the LRU. | ||
| 2821 | For each limit we need to comply with, we need to bump the current number of | ||
| 2822 | files within the limit. If the bump succeeds (results in a current number not | ||
| 2823 | larger than the limit value), we have a right to open a file. | ||
| 2824 | |||
| 2825 | When all rights are acquired the `Fil_shard::open_file` opens the file and | ||
| 2826 | returns true. The file opened will naturally count against the limits. After | ||
| 2827 | this happens, the current values of files for the limits are decreased only in | ||
| 2828 | `Fil_shard::close_file`. */ | ||
| 2829 | |||
| 2830 | /* We remember if we have already acquired right to open the file against the | ||
| 2831 | total open files limit. */ | ||
| 2832 | 306701 | bool have_right_for_open = false; | |
| 2833 | /* As well as the right to open the file against limit for files that do not | ||
| 2834 | take part in LRU algorithm. If the file takes part in LRU algorithm, this | ||
| 2835 | is never true. */ | ||
| 2836 | 306701 | bool have_right_for_open_non_lru = false; | |
| 2837 | |||
| 2838 | /* To acquire a right against a limit, we use this helper function. It | ||
| 2839 | atomically tries to bump the value of supplied reference to a current value | ||
| 2840 | as long as it is below the limit set. Returns true if the right to open is | ||
| 2841 | acquired. */ | ||
| 2842 | 345418 | const auto acquire_right = [](std::atomic<size_t> &counter, | |
| 2843 | size_t limit) -> bool { | ||
| 2844 | 345418 | auto current_count = counter.load(); | |
| 2845 |
2/2✓ Branch 0 taken 340133 times.
✓ Branch 1 taken 5300 times.
|
345433 | while (limit > current_count) { |
| 2846 |
2/2✓ Branch 0 taken 340129 times.
✓ Branch 1 taken 10 times.
|
680272 | if (counter.compare_exchange_weak(current_count, current_count + 1)) { |
| 2847 | 340129 | return true; | |
| 2848 | } | ||
| 2849 | } | ||
| 2850 | 5300 | return false; | |
| 2851 | }; | ||
| 2852 | |||
| 2853 | /* At any point we can decide to release any rights that we have acquired so | ||
| 2854 | far. This will make us unable to open the file now. The | ||
| 2855 | `Fil_shard::open_file()` when returning `false` must assure no rights are | ||
| 2856 | left unreleased - this helper function helps to assure that. */ | ||
| 2857 | 6 | const auto release_rights = [&]() { | |
| 2858 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (have_right_for_open) { |
| 2859 | fil_n_files_open.fetch_sub(1); | ||
| 2860 | ✗ | have_right_for_open = false; | |
| 2861 | } | ||
| 2862 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (have_right_for_open_non_lru) { |
| 2863 | ✗ | ut_ad(fil_system->m_n_files_not_belonging_in_lru.load() > 0); | |
| 2864 | ✗ | fil_system->m_n_files_not_belonging_in_lru.fetch_sub(1); | |
| 2865 | ✗ | have_right_for_open_non_lru = false; | |
| 2866 | } | ||
| 2867 | 306707 | }; | |
| 2868 | |||
| 2869 | /* Helper function: In case of repeated errors, we will delay printing of | ||
| 2870 | any messages to log by PRINT_INTERVAL_SECS after the method processing | ||
| 2871 | starts and then print one message per PRINT_INTERVAL_SECS. */ | ||
| 2872 | const auto should_print_message = | ||
| 2873 | 10604 | [&start_time](ib::Throttler &throttler) -> bool { | |
| 2874 | 5302 | const auto current_time = std::chrono::steady_clock::now(); | |
| 2875 |
3/6✓ Branch 0 taken 5302 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5302 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5302 times.
|
5302 | if (current_time - start_time >= PRINT_INTERVAL) { |
| 2876 | ✗ | return throttler.apply(); | |
| 2877 | } | ||
| 2878 | 5302 | return false; | |
| 2879 | 306701 | }; | |
| 2880 | /* If this is `false`, the file to open will count against the limit for | ||
| 2881 | opened files not taking part in the LRU algorithm. We will need to acquire | ||
| 2882 | a right to open it. */ | ||
| 2883 |
1/2✓ Branch 0 taken 306704 times.
✗ Branch 1 not taken.
|
306701 | const bool belongs_to_lru = Fil_system::space_belongs_in_LRU(file->space); |
| 2884 | |||
| 2885 | /* We remember the current limit for opened files. If it changes while we are | ||
| 2886 | acquiring the rights, we must ensure we have not caused it to be bumped higher | ||
| 2887 | than the new limit. This double checking works together with double checking | ||
| 2888 | in the `Fil_system::set_open_files_limit` to ensure no race conditions are | ||
| 2889 | possible to leave number of opened files over the limit even in an event of | ||
| 2890 | changing the limit in parallel. | ||
| 2891 | |||
| 2892 | The non-LRU files limit can only change when the main limit for open files is | ||
| 2893 | changed, so we monitor only the main one. */ | ||
| 2894 | 306704 | auto last_open_file_limit = fil_system->get_open_files_limit(); | |
| 2895 | |||
| 2896 | /* This is the main loop. It tries to assure all conditions required to open | ||
| 2897 | the file or causes `open_file` to exit if the file is already opened in | ||
| 2898 | different thread. | ||
| 2899 | |||
| 2900 | At this point, start of each loop and upon exit of the loop (either with | ||
| 2901 | `break` or `return`) the shard's mutex is owned by this thread. However, it | ||
| 2902 | may be released and re-acquired in meantime, for a while, inside this loop. If | ||
| 2903 | we decide to release the mutex, we must execute the loop from begin after | ||
| 2904 | re-acquiring it. | ||
| 2905 | |||
| 2906 | The following is the list of conditions we must fulfill to allow file to be | ||
| 2907 | opened: | ||
| 2908 | 1. At any point, if the file becomes open, we just return success. Must be | ||
| 2909 | done under the mutex. | ||
| 2910 | |||
| 2911 | 2. At any point, if the space becomes deleted, we just return failure. Must be | ||
| 2912 | done under the mutex. | ||
| 2913 | |||
| 2914 | 3. If the file is locked with `space->prevent_file_open`, then release any | ||
| 2915 | rights against the limits acquired so far, and wait till the "lock" is | ||
| 2916 | released. The check must be done under the mutex. But the waiting must be | ||
| 2917 | executed only when we don't own the mutex - it is required by other thread to | ||
| 2918 | release the "lock". | ||
| 2919 | |||
| 2920 | 4. Reserve a right within the non-LRU opened files limit. This is conditional | ||
| 2921 | - required only if the file is supposed to not be placed in the opened files | ||
| 2922 | LRU. This is lock-free. | ||
| 2923 | |||
| 2924 | 5. Reserve a right within the fil_system->get_open_files_limit(), | ||
| 2925 | unconditionally. | ||
| 2926 | |||
| 2927 | 6. Check if the limit value for the opened files have not changed. If it did, | ||
| 2928 | we just release all rights and retry from the beginning. | ||
| 2929 | |||
| 2930 | 7. Only then we can proceed with actually opening the file. */ | ||
| 2931 | for (;;) { | ||
| 2932 | /* 1. If the file becomes open, we just return success. We own the mutex, | ||
| 2933 | may have some rights already acquired. */ | ||
| 2934 |
2/4✓ Branch 0 taken 312002 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 312004 times.
|
312001 | ut_ad(mutex_owned()); |
| 2935 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 312000 times.
|
312004 | if (file->is_open) { |
| 2936 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | release_rights(); |
| 2937 | 4 | return true; | |
| 2938 | } | ||
| 2939 | |||
| 2940 | /* 2. If the space becomes deleted, we just return failure. We own the | ||
| 2941 | mutex and may have some rights already acquired.*/ | ||
| 2942 |
2/4✓ Branch 0 taken 311998 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 311998 times.
|
312000 | if (space->is_deleted()) { |
| 2943 | ✗ | release_rights(); | |
| 2944 | ✗ | return false; | |
| 2945 | } | ||
| 2946 | |||
| 2947 | /* 3. If the file is locked with `space->prevent_file_open`. */ | ||
| 2948 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 311996 times.
|
311998 | if (space->prevent_file_open) { |
| 2949 | /* Someone wants to rename the file. We can't have it opened now. | ||
| 2950 | Give CPU to other thread that renames the file. Release any | ||
| 2951 | rights and the mutex before we go to sleep - we will not need it and | ||
| 2952 | someone else will be able to get these or use the mutex to change the | ||
| 2953 | `space->prevent_file_open`. */ | ||
| 2954 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | mutex_release(); |
| 2955 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | release_rights(); |
| 2956 | |||
| 2957 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (should_print_message( |
| 2958 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | space->m_prevent_file_open_wait_message_throttler)) { |
| 2959 | ✗ | ib::warn(ER_IB_MSG_278, space->name, | |
| 2960 | ✗ | (long long)std::chrono::duration_cast<std::chrono::seconds>( | |
| 2961 | ✗ | std::chrono::steady_clock::now() - start_time) | |
| 2962 | ✗ | .count()); | |
| 2963 | } | ||
| 2964 | |||
| 2965 | #ifndef UNIV_HOTBACKUP | ||
| 2966 | /* Wake the I/O handler threads to make sure pending I/O's are performed | ||
| 2967 | */ | ||
| 2968 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | os_aio_simulated_wake_handler_threads(); |
| 2969 | |||
| 2970 | #endif /* UNIV_HOTBACKUP */ | ||
| 2971 | |||
| 2972 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | std::this_thread::sleep_for(std::chrono::milliseconds(1)); |
| 2973 | |||
| 2974 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | mutex_acquire(); |
| 2975 | 2 | continue; | |
| 2976 | } | ||
| 2977 | /* 4. We try to acquire required right for non-LRU file, if it is not taking | ||
| 2978 | part in the LRU algorithm. */ | ||
| 2979 |
3/4✓ Branch 0 taken 33429 times.
✓ Branch 1 taken 278567 times.
✓ Branch 2 taken 33429 times.
✗ Branch 3 not taken.
|
311996 | if (!(belongs_to_lru || have_right_for_open_non_lru)) { |
| 2980 | 33429 | have_right_for_open_non_lru = | |
| 2981 |
1/2✓ Branch 0 taken 33429 times.
✗ Branch 1 not taken.
|
33429 | acquire_right(fil_system->m_n_files_not_belonging_in_lru, |
| 2982 | Fil_system::get_limit_for_non_lru_files( | ||
| 2983 | fil_system->get_open_files_limit())); | ||
| 2984 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33429 times.
|
33429 | if (!have_right_for_open_non_lru) { |
| 2985 | ✗ | mutex_release(); | |
| 2986 | ✗ | if (should_print_message( | |
| 2987 | ✗ | fil_system->m_MANY_NON_LRU_FILES_OPENED_throttler)) { | |
| 2988 | ✗ | ib::warn(ER_IB_WARN_MANY_NON_LRU_FILES_OPENED, | |
| 2989 | ✗ | fil_system->m_n_files_not_belonging_in_lru.load(), | |
| 2990 | ✗ | fil_system->get_open_files_limit()); | |
| 2991 | } | ||
| 2992 | /* Give CPU to other threads that keep files opened. */ | ||
| 2993 | ✗ | std::this_thread::sleep_for(std::chrono::milliseconds(1)); | |
| 2994 | ✗ | mutex_acquire(); | |
| 2995 | ✗ | continue; | |
| 2996 | } | ||
| 2997 | } | ||
| 2998 | |||
| 2999 | /* 5. We try to acquire required right to open file. */ | ||
| 3000 |
2/2✓ Branch 0 taken 311991 times.
✓ Branch 1 taken 5 times.
|
311996 | if (!have_right_for_open) { |
| 3001 | 312000 | have_right_for_open = | |
| 3002 | 311991 | acquire_right(fil_n_files_open, fil_system->get_open_files_limit()); | |
| 3003 |
2/2✓ Branch 0 taken 5300 times.
✓ Branch 1 taken 306700 times.
|
312000 | if (!have_right_for_open) { |
| 3004 |
1/2✓ Branch 0 taken 5300 times.
✗ Branch 1 not taken.
|
5300 | mutex_release(); |
| 3005 | |||
| 3006 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5300 times.
|
5300 | if (should_print_message( |
| 3007 |
1/2✓ Branch 0 taken 5300 times.
✗ Branch 1 not taken.
|
5300 | fil_system->m_TRYING_TO_OPEN_FILE_FOR_LONG_TIME_throttler)) { |
| 3008 | ib::warn warning( | ||
| 3009 | ER_IB_MSG_TRYING_TO_OPEN_FILE_FOR_LONG_TIME, | ||
| 3010 | ✗ | static_cast<long long>( | |
| 3011 | ✗ | std::chrono::duration_cast<std::chrono::seconds>( | |
| 3012 | ✗ | std::chrono::steady_clock::now() - start_time) | |
| 3013 | ✗ | .count()), | |
| 3014 | ✗ | fil_system->get_open_files_limit()); | |
| 3015 | } | ||
| 3016 | |||
| 3017 | /* Flush tablespaces so that we can close modified files in the LRU | ||
| 3018 | list. */ | ||
| 3019 |
1/2✓ Branch 0 taken 5300 times.
✗ Branch 1 not taken.
|
5300 | fil_system->flush_file_spaces(); |
| 3020 | |||
| 3021 |
2/4✓ Branch 0 taken 5300 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5300 times.
|
5300 | if (!fil_system->close_file_in_all_LRU()) { |
| 3022 | ✗ | fil_system->wait_while_ios_in_progress(); | |
| 3023 | } | ||
| 3024 |
1/2✓ Branch 0 taken 5296 times.
✗ Branch 1 not taken.
|
5300 | mutex_acquire(); |
| 3025 | 5296 | continue; | |
| 3026 | 5296 | } | |
| 3027 | } | ||
| 3028 | |||
| 3029 | /* 6. Re-check the open files limit value. This is working in tandem with | ||
| 3030 | double checking the limits in the `set_open_files_limit()`. Either this | ||
| 3031 | thread or one executing `set_open_files_limit()` will spot the limit is | ||
| 3032 | exceeded and rollback to a correct state: either restore limit or release | ||
| 3033 | rights. */ | ||
| 3034 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 306700 times.
|
306705 | if (last_open_file_limit != fil_system->get_open_files_limit()) { |
| 3035 | ✗ | release_rights(); | |
| 3036 | ✗ | last_open_file_limit = fil_system->get_open_files_limit(); | |
| 3037 | ✗ | continue; | |
| 3038 | } | ||
| 3039 | /* 7. If we have all required rights, and checked under the mutex the | ||
| 3040 | file is not open and can be opened, proceed to opening the file. The file | ||
| 3041 | must be opened before we release the mutex again. */ | ||
| 3042 | 306700 | break; | |
| 3043 | 5298 | } | |
| 3044 | |||
| 3045 | /* We have fulfilled all requirements to actually open the file. */ | ||
| 3046 |
2/4✓ Branch 0 taken 306700 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 306700 times.
|
306700 | ut_ad(mutex_owned()); |
| 3047 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 306700 times.
|
306700 | ut_ad(!file->is_open); |
| 3048 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 306696 times.
|
306700 | ut_ad(!space->prevent_file_open); |
| 3049 |
4/6✓ Branch 0 taken 33429 times.
✓ Branch 1 taken 273267 times.
✓ Branch 2 taken 33429 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 306696 times.
|
306696 | ut_ad(belongs_to_lru || have_right_for_open_non_lru); |
| 3050 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 306694 times.
|
306696 | ut_ad(have_right_for_open); |
| 3051 | |||
| 3052 | bool read_only_mode; | ||
| 3053 | |||
| 3054 |
5/6✓ Branch 0 taken 306699 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 198134 times.
✓ Branch 3 taken 108565 times.
✓ Branch 4 taken 245 times.
✓ Branch 5 taken 197889 times.
|
306694 | read_only_mode = !fsp_is_system_temporary(space->id) && srv_read_only_mode; |
| 3055 | |||
| 3056 |
4/4✓ Branch 0 taken 272356 times.
✓ Branch 1 taken 34343 times.
✓ Branch 2 taken 59266 times.
✓ Branch 3 taken 247429 times.
|
579051 | if (file->size == 0 || |
| 3057 |
5/6✓ Branch 0 taken 34551 times.
✓ Branch 1 taken 237805 times.
✓ Branch 2 taken 24927 times.
✓ Branch 3 taken 9624 times.
✓ Branch 4 taken 24931 times.
✗ Branch 5 not taken.
|
297283 | (space->size_in_header == 0 && space->purpose == FIL_TYPE_TABLESPACE && |
| 3058 | 24927 | file == &space->files.front() | |
| 3059 | #ifndef UNIV_HOTBACKUP | ||
| 3060 |
4/6✓ Branch 0 taken 24927 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24927 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24923 times.
✓ Branch 5 taken 4 times.
|
24931 | && undo::is_active(space->id, false) && |
| 3061 | srv_startup_is_before_trx_rollback_phase | ||
| 3062 | #endif /* !UNIV_HOTBACKUP */ | ||
| 3063 | )) { | ||
| 3064 | /* We don't know the file size yet. */ | ||
| 3065 |
1/2✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
|
59266 | dberr_t err = get_file_size(file, read_only_mode); |
| 3066 | |||
| 3067 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
|
59268 | if (err != DB_SUCCESS) { |
| 3068 | /* Release the rights acquired as we failed to open it in the end. | ||
| 3069 | */ | ||
| 3070 | ✗ | release_rights(); | |
| 3071 | ✗ | return false; | |
| 3072 | } | ||
| 3073 | } | ||
| 3074 | |||
| 3075 | /* Open the file for reading and writing, in Windows normally in the | ||
| 3076 | unbuffered async I/O mode, though global variables may make os_file_create() | ||
| 3077 | to fall back to the normal file I/O mode. */ | ||
| 3078 | |||
| 3079 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 306697 times.
|
306697 | if (file->is_raw_disk) { |
| 3080 | file->handle = | ||
| 3081 | ✗ | os_file_create(innodb_data_file_key, file->name, OS_FILE_OPEN_RAW, | |
| 3082 | OS_FILE_AIO, OS_DATA_FILE, read_only_mode, &success); | ||
| 3083 | } else { | ||
| 3084 | file->handle = | ||
| 3085 |
1/2✓ Branch 0 taken 306697 times.
✗ Branch 1 not taken.
|
306697 | os_file_create(innodb_data_file_key, file->name, OS_FILE_OPEN, |
| 3086 | OS_FILE_AIO, OS_DATA_FILE, read_only_mode, &success); | ||
| 3087 | } | ||
| 3088 | |||
| 3089 |
1/2✓ Branch 0 taken 306697 times.
✗ Branch 1 not taken.
|
306697 | if (success) { |
| 3090 |
1/2✓ Branch 0 taken 306700 times.
✗ Branch 1 not taken.
|
306697 | add_to_lru_if_needed(file); |
| 3091 | /* The file is ready for IO. */ | ||
| 3092 | 306700 | file->is_open = true; | |
| 3093 | } else { | ||
| 3094 | /* Release the rights acquired as we failed to open it in the end. */ | ||
| 3095 | ✗ | release_rights(); | |
| 3096 | } | ||
| 3097 | |||
| 3098 | /* We exit with the mutex acquired. The file is assured to remain open only as | ||
| 3099 | long as the mutex is held. Calls, like to `prepare_file_for_io()` are | ||
| 3100 | required to continue to use the file with the mutex released. */ | ||
| 3101 | 306700 | return success; | |
| 3102 | } | ||
| 3103 | |||
| 3104 | 283613 | void Fil_shard::close_file(fil_node_t *file) { | |
| 3105 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 283615 times.
|
283613 | ut_ad(mutex_owned()); |
| 3106 | |||
| 3107 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 283615 times.
|
283615 | ut_a(file->can_be_closed()); |
| 3108 | |||
| 3109 | 283615 | bool ret = os_file_close(file->handle); | |
| 3110 | |||
| 3111 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 283614 times.
|
283614 | ut_a(ret); |
| 3112 | |||
| 3113 | 283614 | file->handle.m_file = (os_file_t)-1; | |
| 3114 | |||
| 3115 | 283614 | file->is_open = false; | |
| 3116 | |||
| 3117 | 283614 | auto old_files_open_count = fil_n_files_open.fetch_sub(1); | |
| 3118 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 283615 times.
|
283614 | ut_a(old_files_open_count > 0); |
| 3119 | |||
| 3120 |
2/2✓ Branch 0 taken 29339 times.
✓ Branch 1 taken 254274 times.
|
283615 | if (!Fil_system::space_belongs_in_LRU(file->space)) { |
| 3121 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29339 times.
|
58678 | ut_ad(fil_system->m_n_files_not_belonging_in_lru.load() > 0); |
| 3122 | |||
| 3123 | 29339 | fil_system->m_n_files_not_belonging_in_lru.fetch_sub(1); | |
| 3124 | } | ||
| 3125 | |||
| 3126 | 283613 | remove_from_LRU(file); | |
| 3127 | 283615 | } | |
| 3128 | |||
| 3129 | 20856 | bool Fil_shard::close_files_in_LRU() { | |
| 3130 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20854 times.
|
20856 | ut_ad(mutex_owned()); |
| 3131 | |||
| 3132 |
2/2✓ Branch 0 taken 5327 times.
✓ Branch 1 taken 15529 times.
|
20856 | for (auto file = UT_LIST_GET_LAST(m_LRU); file != nullptr; |
| 3133 | 2 | file = UT_LIST_GET_PREV(LRU, file)) { | |
| 3134 |
2/2✓ Branch 0 taken 5324 times.
✓ Branch 1 taken 2 times.
|
5327 | if (file->can_be_closed()) { |
| 3135 | 5324 | close_file(file); | |
| 3136 | |||
| 3137 | 5325 | return true; | |
| 3138 | } | ||
| 3139 | } | ||
| 3140 | |||
| 3141 | 15529 | return false; | |
| 3142 | } | ||
| 3143 | |||
| 3144 | 5325 | bool Fil_system::close_file_in_all_LRU() { | |
| 3145 | 5325 | const auto n_shards = m_shards.size(); | |
| 3146 | 5325 | const auto index = m_next_shard_to_close_from_LRU++; | |
| 3147 |
1/2✓ Branch 0 taken 20858 times.
✗ Branch 1 not taken.
|
20858 | for (size_t i = 0; i < n_shards; ++i) { |
| 3148 | 20858 | auto shard = m_shards[(index + i) % n_shards]; | |
| 3149 | 20858 | shard->mutex_acquire(); | |
| 3150 | |||
| 3151 | 20856 | bool success = shard->close_files_in_LRU(); | |
| 3152 | |||
| 3153 | 20856 | shard->mutex_release(); | |
| 3154 | |||
| 3155 |
2/2✓ Branch 0 taken 5325 times.
✓ Branch 1 taken 15534 times.
|
20859 | if (success) { |
| 3156 | 5325 | return true; | |
| 3157 | } | ||
| 3158 | } | ||
| 3159 | |||
| 3160 | ✗ | return false; | |
| 3161 | } | ||
| 3162 | |||
| 3163 | 1405289891 | fil_space_t *Fil_shard::get_space_by_id(space_id_t space_id) const { | |
| 3164 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1405292066 times.
|
1405289891 | ut_ad(mutex_owned()); |
| 3165 | |||
| 3166 |
2/2✓ Branch 0 taken 13370529 times.
✓ Branch 1 taken 1391921537 times.
|
1405292066 | if (space_id == TRX_SYS_SPACE) { |
| 3167 | 13370529 | return fil_space_t::s_sys_space; | |
| 3168 | } | ||
| 3169 | |||
| 3170 | 1391921537 | return get_space_by_id_from_map(space_id); | |
| 3171 | } | ||
| 3172 | |||
| 3173 | /** Prepare to free a file. Remove from the unflushed list if there | ||
| 3174 | are no pending flushes. | ||
| 3175 | @param[in,out] file File instance to free */ | ||
| 3176 | 81490 | void Fil_shard::prepare_to_free_file(fil_node_t *file) { | |
| 3177 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 81490 times.
|
81490 | ut_ad(mutex_owned()); |
| 3178 | |||
| 3179 | 81490 | fil_space_t *space = file->space; | |
| 3180 | |||
| 3181 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 81490 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 81490 times.
|
81490 | if (space->is_in_unflushed_spaces && space_is_flushed(space)) { |
| 3182 | ✗ | space->is_in_unflushed_spaces = false; | |
| 3183 | |||
| 3184 | ✗ | UT_LIST_REMOVE(m_unflushed_spaces, space); | |
| 3185 | } | ||
| 3186 | 81490 | } | |
| 3187 | |||
| 3188 | /** Prepare to free a file object from a tablespace memory cache. | ||
| 3189 | @param[in,out] file Tablespace file | ||
| 3190 | @param[in] space tablespace */ | ||
| 3191 | 361998 | void Fil_shard::file_close_to_free(fil_node_t *file, fil_space_t *space) { | |
| 3192 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 361998 times.
|
361998 | ut_ad(mutex_owned()); |
| 3193 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 361998 times.
|
361998 | ut_a(file->magic_n == FIL_NODE_MAGIC_N); |
| 3194 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 361998 times.
|
361998 | ut_a(file->n_pending_ios == 0); |
| 3195 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 361998 times.
|
361998 | ut_a(!file->is_being_extended); |
| 3196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 361998 times.
|
361998 | ut_a(file->space == space); |
| 3197 | |||
| 3198 |
2/2✓ Branch 0 taken 81490 times.
✓ Branch 1 taken 280508 times.
|
361998 | if (file->is_open) { |
| 3199 | /* We fool the assertion in Fil_system::close_file() to think | ||
| 3200 | there are no unflushed modifications in the file */ | ||
| 3201 | |||
| 3202 | 81490 | file->set_flushed(); | |
| 3203 | |||
| 3204 | 81490 | os_event_set(file->sync_event); | |
| 3205 | |||
| 3206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 81490 times.
|
81490 | if (fil_disable_space_flushing(space)) { |
| 3207 | ✗ | ut_ad(!space->is_in_unflushed_spaces); | |
| 3208 | ✗ | ut_ad(space_is_flushed(space)); | |
| 3209 | |||
| 3210 | } else { | ||
| 3211 | 81490 | prepare_to_free_file(file); | |
| 3212 | } | ||
| 3213 | |||
| 3214 | 81490 | close_file(file); | |
| 3215 | } | ||
| 3216 | 361998 | } | |
| 3217 | |||
| 3218 | 361970 | void Fil_shard::space_detach(fil_space_t *space) { | |
| 3219 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 361970 times.
|
361970 | ut_ad(mutex_owned()); |
| 3220 | |||
| 3221 | 361970 | m_names.erase(space->name); | |
| 3222 | |||
| 3223 |
2/2✓ Branch 0 taken 817 times.
✓ Branch 1 taken 361153 times.
|
361970 | if (space->is_in_unflushed_spaces) { |
| 3224 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 817 times.
|
817 | ut_ad(!fil_disable_space_flushing(space)); |
| 3225 | |||
| 3226 | 817 | space->is_in_unflushed_spaces = false; | |
| 3227 | |||
| 3228 | 817 | UT_LIST_REMOVE(m_unflushed_spaces, space); | |
| 3229 | } | ||
| 3230 | |||
| 3231 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 361970 times.
|
361970 | if (space->is_in_rotation_list) { |
| 3232 | ✗ | UT_LIST_REMOVE(m_rotation_list, space); | |
| 3233 | ✗ | space->is_in_rotation_list = false; | |
| 3234 | } | ||
| 3235 | |||
| 3236 | 361970 | UT_LIST_REMOVE(m_space_list, space); | |
| 3237 | |||
| 3238 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 361970 times.
|
361970 | ut_a(space->magic_n == FIL_SPACE_MAGIC_N); |
| 3239 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 361970 times.
|
361970 | ut_a(space->n_pending_flushes == 0); |
| 3240 | |||
| 3241 |
2/2✓ Branch 0 taken 361998 times.
✓ Branch 1 taken 361970 times.
|
723968 | for (auto &file : space->files) { |
| 3242 |
1/2✓ Branch 0 taken 361998 times.
✗ Branch 1 not taken.
|
361998 | file_close_to_free(&file, space); |
| 3243 | } | ||
| 3244 | 361970 | } | |
| 3245 | |||
| 3246 | /** Free a tablespace object on which fil_space_detach() was invoked. | ||
| 3247 | There must not be any pending I/O's or flushes on the files. | ||
| 3248 | @param[in,out] space tablespace */ | ||
| 3249 | 360122 | void Fil_shard::space_free_low(fil_space_t *&space) { | |
| 3250 | /* Wait for fil_space_t::release_for_io(); */ | ||
| 3251 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 360122 times.
|
360122 | while (space->n_pending_ios) { |
| 3252 | ✗ | std::this_thread::sleep_for(std::chrono::microseconds(100)); | |
| 3253 | } | ||
| 3254 | |||
| 3255 | #ifndef UNIV_HOTBACKUP | ||
| 3256 | { | ||
| 3257 | /* Temporary and undo tablespaces IDs are assigned from a large but | ||
| 3258 | fixed size pool of reserved IDs. Therefore we must ensure that a | ||
| 3259 | fil_space_t instance can't be dropped until all the pages that point | ||
| 3260 | to it are also purged from the buffer pool. */ | ||
| 3261 | |||
| 3262 |
4/6✓ Branch 0 taken 181544 times.
✓ Branch 1 taken 178578 times.
✓ Branch 2 taken 181544 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 360122 times.
|
360122 | ut_a(srv_shutdown_state.load() == SRV_SHUTDOWN_LAST_PHASE || |
| 3263 | space->has_no_references()); | ||
| 3264 | } | ||
| 3265 | #endif /* !UNIV_HOTBACKUP */ | ||
| 3266 | |||
| 3267 |
2/2✓ Branch 0 taken 360150 times.
✓ Branch 1 taken 360122 times.
|
720272 | for (auto &file : space->files) { |
| 3268 | 360150 | ut_d(space->size -= file.size); | |
| 3269 | |||
| 3270 |
1/2✓ Branch 0 taken 360150 times.
✗ Branch 1 not taken.
|
360150 | os_event_destroy(file.sync_event); |
| 3271 | |||
| 3272 | 360150 | ut::free(file.name); | |
| 3273 | } | ||
| 3274 | |||
| 3275 | 360122 | call_destructor(&space->files); | |
| 3276 | |||
| 3277 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 360122 times.
|
360122 | ut_ad(space->size == 0); |
| 3278 | |||
| 3279 | 360122 | rw_lock_free(&space->latch); | |
| 3280 | |||
| 3281 | 360122 | fil_space_destroy_crypt_data(&space->crypt_data); | |
| 3282 | |||
| 3283 | 360122 | ut::free(space->name); | |
| 3284 | 360122 | ut::free(space); | |
| 3285 | |||
| 3286 | 360122 | space = nullptr; | |
| 3287 | 360122 | } | |
| 3288 | |||
| 3289 | /** Frees a space object from the tablespace memory cache. | ||
| 3290 | Closes a tablespaces' files but does not delete them. | ||
| 3291 | There must not be any pending I/O's or flushes on the files. | ||
| 3292 | @param[in] space_id Tablespace ID | ||
| 3293 | @return fil_space_t instance on success or nullptr */ | ||
| 3294 | 2 | fil_space_t *Fil_shard::space_free(space_id_t space_id) { | |
| 3295 | 2 | mutex_acquire(); | |
| 3296 | |||
| 3297 | 2 | fil_space_t *space = get_space_by_id(space_id); | |
| 3298 | |||
| 3299 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (space != nullptr) { |
| 3300 | ✗ | space_detach(space); | |
| 3301 | |||
| 3302 | ✗ | space_remove_from_lookup_maps(space_id); | |
| 3303 | } | ||
| 3304 | |||
| 3305 | 2 | mutex_release(); | |
| 3306 | |||
| 3307 | 2 | return space; | |
| 3308 | } | ||
| 3309 | |||
| 3310 | /** Frees a space object from the tablespace memory cache. | ||
| 3311 | Closes a tablespaces' files but does not delete them. | ||
| 3312 | There must not be any pending i/o's or flushes on the files. | ||
| 3313 | @param[in] space_id Tablespace ID | ||
| 3314 | @param[in] x_latched Whether the caller holds X-mode space->latch | ||
| 3315 | @return true if success */ | ||
| 3316 | 2 | static bool fil_space_free(space_id_t space_id, bool x_latched) { | |
| 3317 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | ut_ad(space_id != TRX_SYS_SPACE); |
| 3318 | |||
| 3319 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | auto shard = fil_system->shard_by_id(space_id); |
| 3320 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | auto space = shard->space_free(space_id); |
| 3321 | |||
| 3322 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (space == nullptr) { |
| 3323 | 2 | return false; | |
| 3324 | } | ||
| 3325 | |||
| 3326 | ✗ | if (x_latched) { | |
| 3327 | ✗ | rw_lock_x_unlock(&space->latch); | |
| 3328 | } | ||
| 3329 | |||
| 3330 | ✗ | shard->mutex_acquire(); | |
| 3331 | ✗ | Fil_shard::space_free_low(space); | |
| 3332 | ✗ | shard->mutex_release(); | |
| 3333 | |||
| 3334 | ✗ | ut_a(space == nullptr); | |
| 3335 | |||
| 3336 | ✗ | return true; | |
| 3337 | } | ||
| 3338 | |||
| 3339 | #ifdef UNIV_HOTBACKUP | ||
| 3340 | /** Frees a space object from the tablespace memory cache. | ||
| 3341 | Closes a tablespaces' files but does not delete them. | ||
| 3342 | There must not be any pending i/o's or flushes on the files. | ||
| 3343 | @param[in] space_id Tablespace ID | ||
| 3344 | @return true if success */ | ||
| 3345 | bool meb_fil_space_free(space_id_t space_id) { | ||
| 3346 | return fil_space_free(space_id, false); | ||
| 3347 | } | ||
| 3348 | #endif /* UNIV_HOTBACKUP */ | ||
| 3349 | |||
| 3350 | /** Create a space memory object and put it to the fil_system hash table. | ||
| 3351 | The tablespace name is independent from the tablespace file-name. | ||
| 3352 | Error messages are issued to the server log. | ||
| 3353 | @param[in] name Tablespace name | ||
| 3354 | @param[in] space_id Tablespace identifier | ||
| 3355 | @param[in] flags Tablespace flags | ||
| 3356 | @param[in] purpose Tablespace purpose | ||
| 3357 | @return pointer to created tablespace, to be filled in with fil_node_create() | ||
| 3358 | @retval nullptr on failure (such as when the same tablespace exists) */ | ||
| 3359 | 393130 | fil_space_t *Fil_shard::space_create(const char *name, space_id_t space_id, | |
| 3360 | uint32_t flags, fil_type_t purpose, | ||
| 3361 | fil_space_crypt_t *crypt_data, | ||
| 3362 | fil_encryption_t mode) { | ||
| 3363 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 393130 times.
|
393130 | ut_ad(mutex_owned()); |
| 3364 | |||
| 3365 | /* Look for a matching tablespace. */ | ||
| 3366 | 393130 | fil_space_t *space = get_space_by_name(name); | |
| 3367 | |||
| 3368 |
1/2✓ Branch 0 taken 393130 times.
✗ Branch 1 not taken.
|
393130 | if (space == nullptr) { |
| 3369 | 393130 | space = get_space_by_id(space_id); | |
| 3370 | } | ||
| 3371 | |||
| 3372 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 393130 times.
|
393130 | if (space != nullptr) { |
| 3373 | ✗ | std::ostringstream oss; | |
| 3374 | |||
| 3375 | ✗ | for (size_t i = 0; i < space->files.size(); ++i) { | |
| 3376 | ✗ | oss << "'" << space->files[i].name << "'"; | |
| 3377 | |||
| 3378 | ✗ | if (i < space->files.size() - 1) { | |
| 3379 | ✗ | oss << ", "; | |
| 3380 | } | ||
| 3381 | } | ||
| 3382 | |||
| 3383 | ✗ | ut_ad(space->id != space_id); | |
| 3384 | ✗ | ib::info(ER_IB_MSG_281) | |
| 3385 | ✗ | << "Trying to add tablespace '" << name << "'" | |
| 3386 | ✗ | << " with id " << space_id << " to the tablespace" | |
| 3387 | ✗ | << " memory cache, but tablespace" | |
| 3388 | ✗ | << " '" << space->name << "'" | |
| 3389 | ✗ | << " already exists in the cache with space ID " << space->id | |
| 3390 | ✗ | << ". It maps to the following file(s): " << oss.str(); | |
| 3391 | |||
| 3392 | ✗ | return nullptr; | |
| 3393 | } | ||
| 3394 | |||
| 3395 | space = static_cast<fil_space_t *>( | ||
| 3396 | 393130 | ut::zalloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, sizeof(*space))); | |
| 3397 | /* This could be just a placement new constructor call if, only if it compiles | ||
| 3398 | OK on SunPro. */ | ||
| 3399 | 393130 | space->initialize(); | |
| 3400 | |||
| 3401 | 393130 | space->id = space_id; | |
| 3402 | 393130 | space->name = mem_strdup(name); | |
| 3403 | |||
| 3404 | #ifndef UNIV_HOTBACKUP | ||
| 3405 |
2/2✓ Branch 0 taken 130941 times.
✓ Branch 1 taken 9404 times.
|
533475 | if (fil_system->is_greater_than_max_id(space_id) && !recv_recovery_on && |
| 3406 |
4/6✓ Branch 0 taken 140345 times.
✓ Branch 1 taken 252785 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 130941 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 393130 times.
|
533475 | !dict_sys_t::is_reserved(space_id) && |
| 3407 | ✗ | !fsp_is_system_temporary(space_id)) { | |
| 3408 | ✗ | fil_system->set_maximum_space_id(space); | |
| 3409 | } | ||
| 3410 | #endif /* !UNIV_HOTBACKUP */ | ||
| 3411 | |||
| 3412 | 393130 | space->purpose = purpose; | |
| 3413 | |||
| 3414 | 393130 | space->crypt_data = crypt_data; | |
| 3415 | |||
| 3416 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 393130 times.
|
393130 | ut_a(flags < std::numeric_limits<uint32_t>::max()); |
| 3417 | 393130 | space->flags = (uint32_t)flags; | |
| 3418 | |||
| 3419 | 393130 | space->magic_n = FIL_SPACE_MAGIC_N; | |
| 3420 | |||
| 3421 | 393130 | space->m_encryption_metadata.m_type = Encryption::NONE; | |
| 3422 | 393130 | space->encryption_op_in_progress = Encryption::Progress::NONE; | |
| 3423 | |||
| 3424 | 393130 | rw_lock_create(fil_space_latch_key, &space->latch, SYNC_FSP); | |
| 3425 | |||
| 3426 | 393130 | space->is_corrupt = false; | |
| 3427 | |||
| 3428 | 393130 | space->is_space_encrypted = false; | |
| 3429 | |||
| 3430 | 393130 | space->exclude_from_rotation = false; | |
| 3431 | |||
| 3432 | #ifndef UNIV_HOTBACKUP | ||
| 3433 |
2/2✓ Branch 0 taken 106324 times.
✓ Branch 1 taken 286806 times.
|
393130 | if (space->purpose == FIL_TYPE_TEMPORARY) { |
| 3434 | 106324 | ut_d(space->latch.set_temp_fsp()); | |
| 3435 | } | ||
| 3436 | #endif /* !UNIV_HOTBACKUP */ | ||
| 3437 | |||
| 3438 | 393130 | space_add(space, mode); | |
| 3439 | |||
| 3440 | 393130 | return space; | |
| 3441 | } | ||
| 3442 | |||
| 3443 | /** Create a space memory object and put it to the fil_system hash table. | ||
| 3444 | The tablespace name is independent from the tablespace file-name. | ||
| 3445 | Error messages are issued to the server log. | ||
| 3446 | @param[in] name Tablespace name | ||
| 3447 | @param[in] space_id Tablespace ID | ||
| 3448 | @param[in] flags Tablespace flags | ||
| 3449 | @param[in] purpose Tablespace purpose | ||
| 3450 | @return pointer to created tablespace, to be filled in with fil_node_create() | ||
| 3451 | @retval nullptr on failure (such as when the same tablespace exists) */ | ||
| 3452 | 383713 | fil_space_t *fil_space_create(const char *name, space_id_t space_id, | |
| 3453 | uint32_t flags, fil_type_t purpose, | ||
| 3454 | fil_space_crypt_t *crypt_data, | ||
| 3455 | fil_encryption_t mode) { | ||
| 3456 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 383713 times.
|
383713 | ut_ad(fsp_flags_is_valid(flags)); |
| 3457 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 383713 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 383713 times.
|
383713 | ut_ad(srv_page_size == UNIV_PAGE_SIZE_ORIG || flags != 0); |
| 3458 | |||
| 3459 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 383711 times.
|
383713 | DBUG_EXECUTE_IF("fil_space_create_failure", return nullptr;); |
| 3460 | |||
| 3461 | 383711 | fil_system->mutex_acquire_all(); | |
| 3462 | |||
| 3463 | 383711 | auto shard = fil_system->shard_by_id(space_id); | |
| 3464 | |||
| 3465 | auto space = | ||
| 3466 | 383711 | shard->space_create(name, space_id, flags, purpose, crypt_data, mode); | |
| 3467 | |||
| 3468 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 383711 times.
|
383711 | if (space == nullptr) { |
| 3469 | /* Duplicate error. */ | ||
| 3470 | ✗ | fil_system->mutex_release_all(); | |
| 3471 | ✗ | return nullptr; | |
| 3472 | } | ||
| 3473 | |||
| 3474 | /* Cache the system tablespaces, avoid looking them up during IO. */ | ||
| 3475 | |||
| 3476 |
2/2✓ Branch 0 taken 9686 times.
✓ Branch 1 taken 374025 times.
|
383711 | if (space->id == TRX_SYS_SPACE) { |
| 3477 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 9686 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9686 times.
|
9686 | ut_a(fil_space_t::s_sys_space == nullptr || |
| 3478 | fil_space_t::s_sys_space == space); | ||
| 3479 | |||
| 3480 | 9686 | fil_space_t::s_sys_space = space; | |
| 3481 | } | ||
| 3482 | |||
| 3483 | 383711 | fil_system->mutex_release_all(); | |
| 3484 | |||
| 3485 | 383711 | return space; | |
| 3486 | } | ||
| 3487 | |||
| 3488 | /** Assigns a new space id for a new single-table tablespace. This | ||
| 3489 | works simply by incrementing the global counter. If 4 billion ids | ||
| 3490 | is not enough, we may need to recycle ids. | ||
| 3491 | @param[out] space_id Set this to the new tablespace ID | ||
| 3492 | @return true if assigned, false if not */ | ||
| 3493 | 196997 | bool Fil_system::assign_new_space_id(space_id_t *space_id) { | |
| 3494 |
1/2✓ Branch 0 taken 196997 times.
✗ Branch 1 not taken.
|
196997 | mutex_acquire_all(); |
| 3495 | |||
| 3496 | 196997 | space_id_t id = *space_id; | |
| 3497 | |||
| 3498 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 196997 times.
|
196997 | if (id < m_max_assigned_id) { |
| 3499 | ✗ | id = m_max_assigned_id; | |
| 3500 | } | ||
| 3501 | |||
| 3502 | 196997 | ++id; | |
| 3503 | |||
| 3504 | 196997 | space_id_t reserved_space_id = dict_sys_t::s_reserved_space_id; | |
| 3505 | |||
| 3506 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 196997 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
196997 | if (id > (reserved_space_id / 2) && (id % 1000000UL == 0)) { |
| 3507 | ✗ | ib::warn(ER_IB_MSG_282) | |
| 3508 | << "You are running out of new single-table" | ||
| 3509 | ✗ | " tablespace id's. Current counter is " | |
| 3510 | ✗ | << id << " and it must not exceed " << reserved_space_id | |
| 3511 | << "! To reset the counter to zero you have to dump" | ||
| 3512 | " all your tables and recreate the whole InnoDB" | ||
| 3513 | ✗ | " installation."; | |
| 3514 | } | ||
| 3515 | |||
| 3516 | 196997 | bool success = !dict_sys_t::is_reserved(id); | |
| 3517 | |||
| 3518 |
1/2✓ Branch 0 taken 196997 times.
✗ Branch 1 not taken.
|
196997 | if (success) { |
| 3519 | 196997 | *space_id = m_max_assigned_id = id; | |
| 3520 | |||
| 3521 | } else { | ||
| 3522 | ✗ | ib::warn(ER_IB_MSG_283) << "You have run out of single-table tablespace" | |
| 3523 | ✗ | " id's! Current counter is " | |
| 3524 | ✗ | << id | |
| 3525 | << ". To reset the counter to zero" | ||
| 3526 | " you have to dump all your tables and" | ||
| 3527 | ✗ | " recreate the whole InnoDB installation."; | |
| 3528 | |||
| 3529 | ✗ | *space_id = SPACE_UNKNOWN; | |
| 3530 | } | ||
| 3531 | |||
| 3532 |
1/2✓ Branch 0 taken 196997 times.
✗ Branch 1 not taken.
|
196997 | mutex_release_all(); |
| 3533 | |||
| 3534 | 196997 | return success; | |
| 3535 | } | ||
| 3536 | |||
| 3537 | /** Assigns a new space id for a new single-table tablespace. This works | ||
| 3538 | simply by incrementing the global counter. If 4 billion id's is not enough, | ||
| 3539 | we may need to recycle id's. | ||
| 3540 | @param[out] space_id Set this to the new tablespace ID | ||
| 3541 | @return true if assigned, false if not */ | ||
| 3542 | 196997 | bool fil_assign_new_space_id(space_id_t *space_id) { | |
| 3543 | 196997 | return fil_system->assign_new_space_id(space_id); | |
| 3544 | } | ||
| 3545 | |||
| 3546 | /** Open the files associated with a tablespace, make sure the size of | ||
| 3547 | the tablespace is read from the header page, and return a pointer to the | ||
| 3548 | fil_space_t that is in the memory cache associated with the given space id. | ||
| 3549 | @param[in] space_id Get the tablespace instance or this ID | ||
| 3550 | @return file_space_t pointer, nullptr if space not found */ | ||
| 3551 | 425198557 | fil_space_t *Fil_shard::space_load(space_id_t space_id) { | |
| 3552 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1059146043 times.
|
425198557 | ut_ad(mutex_owned()); |
| 3553 | |||
| 3554 | 1059146043 | fil_space_t *space = get_space_by_id(space_id); | |
| 3555 | |||
| 3556 |
4/4✓ Branch 0 taken 1059133654 times.
✓ Branch 1 taken 7766 times.
✓ Branch 2 taken 1059100980 times.
✓ Branch 3 taken 32674 times.
|
1059141420 | if (space == nullptr || space->size != 0) { |
| 3557 | 1059108746 | return space; | |
| 3558 | } | ||
| 3559 | |||
| 3560 |
1/2✓ Branch 0 taken 32674 times.
✗ Branch 1 not taken.
|
32674 | switch (space->purpose) { |
| 3561 | 32674 | case FIL_TYPE_IMPORT: | |
| 3562 | case FIL_TYPE_TEMPORARY: | ||
| 3563 | case FIL_TYPE_TABLESPACE: | ||
| 3564 | |||
| 3565 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32673 times.
|
32674 | ut_a(space_id != TRX_SYS_SPACE); |
| 3566 | |||
| 3567 | 32673 | space = get_space_by_id(space_id); | |
| 3568 | |||
| 3569 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32674 times.
|
32674 | if (space == nullptr) { |
| 3570 | ✗ | return nullptr; | |
| 3571 | } | ||
| 3572 | |||
| 3573 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32674 times.
|
32674 | ut_a(1 == space->files.size()); |
| 3574 | |||
| 3575 | { | ||
| 3576 | 32674 | auto file = &space->files.front(); | |
| 3577 | |||
| 3578 | /* It must be a single-table tablespace and | ||
| 3579 | we have not opened the file yet; the following | ||
| 3580 | calls will open it and update the size fields */ | ||
| 3581 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32673 times.
|
32673 | if (!prepare_file_for_io(file)) { |
| 3582 | /* The single-table tablespace can't be opened, | ||
| 3583 | because the ibd file is missing. */ | ||
| 3584 | |||
| 3585 | ✗ | return nullptr; | |
| 3586 | } | ||
| 3587 | |||
| 3588 |
1/2✓ Branch 0 taken 32674 times.
✗ Branch 1 not taken.
|
32673 | complete_io(file, IORequestRead); |
| 3589 | } | ||
| 3590 | } | ||
| 3591 | |||
| 3592 | 32674 | return space; | |
| 3593 | } | ||
| 3594 | |||
| 3595 | /** Returns the path from the first fil_node_t found with this space ID. | ||
| 3596 | The caller is responsible for freeing the memory allocated here for the | ||
| 3597 | value returned. | ||
| 3598 | @param[in] space_id Tablespace ID | ||
| 3599 | @return own: A copy of fil_node_t::path, nullptr if space ID is zero | ||
| 3600 | or not found. */ | ||
| 3601 | 464490 | char *fil_space_get_first_path(space_id_t space_id) { | |
| 3602 | 464490 | auto shard = fil_system->shard_by_id(space_id); | |
| 3603 | |||
| 3604 | 464490 | shard->mutex_acquire(); | |
| 3605 | |||
| 3606 | 464490 | fil_space_t *space = shard->space_load(space_id); | |
| 3607 | |||
| 3608 | char *path; | ||
| 3609 | |||
| 3610 |
2/2✓ Branch 0 taken 463291 times.
✓ Branch 1 taken 1199 times.
|
464490 | if (space != nullptr) { |
| 3611 | 463291 | path = mem_strdup(space->files.front().name); | |
| 3612 | } else { | ||
| 3613 | 1199 | path = nullptr; | |
| 3614 | } | ||
| 3615 | |||
| 3616 | 464490 | shard->mutex_release(); | |
| 3617 | |||
| 3618 | 464490 | return path; | |
| 3619 | } | ||
| 3620 | |||
| 3621 | /** Returns the size of the space in pages. The tablespace must be cached | ||
| 3622 | in the memory cache. | ||
| 3623 | @param[in] space_id Tablespace ID | ||
| 3624 | @return space size, 0 if space not found */ | ||
| 3625 | 72669 | page_no_t fil_space_get_size(space_id_t space_id) { | |
| 3626 | 72669 | auto shard = fil_system->shard_by_id(space_id); | |
| 3627 | |||
| 3628 | 72669 | shard->mutex_acquire(); | |
| 3629 | |||
| 3630 | 72669 | fil_space_t *space = shard->space_load(space_id); | |
| 3631 | |||
| 3632 |
2/2✓ Branch 0 taken 72668 times.
✓ Branch 1 taken 1 times.
|
72669 | page_no_t size = space ? space->size : 0; |
| 3633 | |||
| 3634 | 72669 | shard->mutex_release(); | |
| 3635 | |||
| 3636 | 72669 | return size; | |
| 3637 | } | ||
| 3638 | |||
| 3639 | 104778 | page_no_t fil_space_get_undo_initial_size(space_id_t space_id) { | |
| 3640 | 104778 | auto shard = fil_system->shard_by_id(space_id); | |
| 3641 | |||
| 3642 | 104778 | shard->mutex_acquire(); | |
| 3643 | |||
| 3644 | 104778 | fil_space_t *space = shard->space_load(space_id); | |
| 3645 | |||
| 3646 |
1/2✓ Branch 0 taken 104778 times.
✗ Branch 1 not taken.
|
104778 | page_no_t size = space ? space->m_undo_initial : 0; |
| 3647 | |||
| 3648 | 104778 | shard->mutex_release(); | |
| 3649 | |||
| 3650 | 104778 | return size; | |
| 3651 | } | ||
| 3652 | |||
| 3653 | 39219 | void fil_space_set_undo_size(space_id_t space_id, bool use_current) { | |
| 3654 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39219 times.
|
39219 | ut_ad(fsp_is_undo_tablespace(space_id)); |
| 3655 | |||
| 3656 | 39219 | auto shard = fil_system->shard_by_id(space_id); | |
| 3657 | |||
| 3658 | 39219 | shard->mutex_acquire(); | |
| 3659 | |||
| 3660 | 39219 | fil_space_t *space = shard->space_load(space_id); | |
| 3661 | |||
| 3662 |
1/2✓ Branch 0 taken 39219 times.
✗ Branch 1 not taken.
|
39219 | if (space != nullptr) { |
| 3663 |
2/2✓ Branch 0 taken 20291 times.
✓ Branch 1 taken 18928 times.
|
39219 | space->m_undo_initial = |
| 3664 | 18928 | (use_current ? space->size : UNDO_INITIAL_SIZE_IN_PAGES); | |
| 3665 | 39219 | space->m_undo_extend = UNDO_INITIAL_SIZE_IN_PAGES; | |
| 3666 | } | ||
| 3667 | |||
| 3668 | 39219 | shard->mutex_release(); | |
| 3669 | 39219 | } | |
| 3670 | |||
| 3671 | /** Returns the flags of the space. The tablespace must be cached | ||
| 3672 | in the memory cache. | ||
| 3673 | @param[in] space_id Tablespace ID for which to get the flags | ||
| 3674 | @return flags, ULINT_UNDEFINED if space not found */ | ||
| 3675 | 1058175077 | uint32_t fil_space_get_flags(space_id_t space_id) { | |
| 3676 | 1058175077 | auto shard = fil_system->shard_by_id(space_id); | |
| 3677 | |||
| 3678 | 1058178168 | shard->mutex_acquire(); | |
| 3679 | |||
| 3680 | 1058191974 | fil_space_t *space = shard->space_load(space_id); | |
| 3681 | |||
| 3682 | uint32_t flags; | ||
| 3683 | |||
| 3684 |
2/2✓ Branch 0 taken 1058180007 times.
✓ Branch 1 taken 6816 times.
|
1058186823 | flags = (space != nullptr) ? space->flags : UINT32_UNDEFINED; |
| 3685 | |||
| 3686 | 1058186823 | shard->mutex_release(); | |
| 3687 | |||
| 3688 | 1058198815 | return flags; | |
| 3689 | } | ||
| 3690 | |||
| 3691 | /** Open each file of a tablespace if not already open. | ||
| 3692 | @param[in] space_id tablespace identifier | ||
| 3693 | @retval true if all file nodes were opened | ||
| 3694 | @retval false on failure */ | ||
| 3695 | 35013 | bool Fil_shard::space_open(space_id_t space_id) { | |
| 3696 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35013 times.
|
35013 | ut_ad(mutex_owned()); |
| 3697 | |||
| 3698 | 35013 | fil_space_t *space = get_space_by_id(space_id); | |
| 3699 | |||
| 3700 |
2/2✓ Branch 0 taken 35013 times.
✓ Branch 1 taken 35013 times.
|
70026 | for (auto &file : space->files) { |
| 3701 |
5/8✓ Branch 0 taken 29838 times.
✓ Branch 1 taken 5175 times.
✓ Branch 2 taken 29838 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 29838 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 35013 times.
|
35013 | if (!file.is_open && !open_file(&file)) { |
| 3702 | ✗ | return false; | |
| 3703 | } | ||
| 3704 | } | ||
| 3705 | |||
| 3706 | 35013 | return true; | |
| 3707 | } | ||
| 3708 | |||
| 3709 | /** Open each file of a tablespace if not already open. | ||
| 3710 | @param[in] space_id Tablespace ID | ||
| 3711 | @retval true if all file nodes were opened | ||
| 3712 | @retval false on failure */ | ||
| 3713 | 35013 | bool fil_space_open(space_id_t space_id) { | |
| 3714 | 35013 | auto shard = fil_system->shard_by_id(space_id); | |
| 3715 | |||
| 3716 | 35013 | shard->mutex_acquire(); | |
| 3717 | |||
| 3718 | 35013 | bool success = shard->space_open(space_id); | |
| 3719 | |||
| 3720 | 35013 | shard->mutex_release(); | |
| 3721 | |||
| 3722 | 35013 | return success; | |
| 3723 | } | ||
| 3724 | |||
| 3725 | /** Close each file of a tablespace if open. | ||
| 3726 | @param[in] space_id Tablespace ID */ | ||
| 3727 | 178363 | void fil_space_close(space_id_t space_id) { | |
| 3728 |
2/2✓ Branch 0 taken 8267 times.
✓ Branch 1 taken 170096 times.
|
178363 | if (fil_system == nullptr) { |
| 3729 | 8267 | return; | |
| 3730 | } | ||
| 3731 | |||
| 3732 | 170096 | auto shard = fil_system->shard_by_id(space_id); | |
| 3733 | |||
| 3734 | 170096 | shard->close_file(space_id); | |
| 3735 | } | ||
| 3736 | |||
| 3737 | /** Returns the page size of the space and whether it is compressed or not. | ||
| 3738 | The tablespace must be cached in the memory cache. | ||
| 3739 | @param[in] space_id Tablespace ID | ||
| 3740 | @param[out] found true if tablespace was found | ||
| 3741 | @return page size */ | ||
| 3742 | 1057783328 | const page_size_t fil_space_get_page_size(space_id_t space_id, bool *found) { | |
| 3743 | 1057783328 | const uint32_t flags = fil_space_get_flags(space_id); | |
| 3744 | |||
| 3745 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 1057813020 times.
|
1057813070 | if (flags == UINT32_UNDEFINED) { |
| 3746 | 50 | *found = false; | |
| 3747 | 50 | return univ_page_size; | |
| 3748 | } | ||
| 3749 | |||
| 3750 | 1057813020 | *found = true; | |
| 3751 | |||
| 3752 | 1057813020 | return page_size_t(flags); | |
| 3753 | } | ||
| 3754 | |||
| 3755 | /** Initializes the tablespace memory cache. | ||
| 3756 | @param[in] max_n_open Maximum number of open files */ | ||
| 3757 | 9805 | void fil_init(ulint max_n_open) { | |
| 3758 | static_assert((1 << UNIV_PAGE_SIZE_SHIFT_MAX) == UNIV_PAGE_SIZE_MAX, | ||
| 3759 | "(1 << UNIV_PAGE_SIZE_SHIFT_MAX) != UNIV_PAGE_SIZE_MAX"); | ||
| 3760 | |||
| 3761 | static_assert((1 << UNIV_PAGE_SIZE_SHIFT_MIN) == UNIV_PAGE_SIZE_MIN, | ||
| 3762 | "(1 << UNIV_PAGE_SIZE_SHIFT_MIN) != UNIV_PAGE_SIZE_MIN"); | ||
| 3763 | |||
| 3764 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9805 times.
|
9805 | ut_a(fil_system == nullptr); |
| 3765 | |||
| 3766 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9805 times.
|
9805 | ut_a(max_n_open > 0); |
| 3767 | |||
| 3768 | 9805 | fil_system = ut::new_withkey<Fil_system>(UT_NEW_THIS_FILE_PSI_KEY, MAX_SHARDS, | |
| 3769 | max_n_open); | ||
| 3770 | |||
| 3771 | 9805 | fil_space_crypt_init(); | |
| 3772 | 9805 | } | |
| 3773 | |||
| 3774 | 16 | bool fil_open_files_limit_update(size_t &new_max_open_files) { | |
| 3775 | 16 | return fil_system->set_open_files_limit(new_max_open_files); | |
| 3776 | } | ||
| 3777 | |||
| 3778 | 16 | bool Fil_system::set_open_files_limit(size_t &new_max_open_files) { | |
| 3779 | 16 | const auto start_time = std::chrono::steady_clock::now(); | |
| 3780 | { | ||
| 3781 | const auto current_minimum_limit_for_open_files = | ||
| 3782 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | get_minimum_limit_for_open_files(m_n_files_not_belonging_in_lru); |
| 3783 | |||
| 3784 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 13 times.
|
16 | if (new_max_open_files < current_minimum_limit_for_open_files) { |
| 3785 | /* Use the same value that was used for the check, to not mislead user | ||
| 3786 | with other value than was used in calculations. */ | ||
| 3787 | 3 | new_max_open_files = current_minimum_limit_for_open_files; | |
| 3788 | 3 | return false; | |
| 3789 | } | ||
| 3790 | } | ||
| 3791 | /* We impose our new limit to not allow new file openings to cross new limits | ||
| 3792 | (including non-LRU limit). */ | ||
| 3793 |
3/4✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 12 times.
|
13 | if (!m_open_files_limit.set_desired_limit(new_max_open_files)) { |
| 3794 | 1 | new_max_open_files = 0; | |
| 3795 | 1 | return false; | |
| 3796 | } | ||
| 3797 | |||
| 3798 | /* We read the m_n_files_not_belonging_in_lru again after the | ||
| 3799 | m_open_files_limit write is issued. */ | ||
| 3800 | const auto current_minimum_limit_for_open_files = | ||
| 3801 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | get_minimum_limit_for_open_files(m_n_files_not_belonging_in_lru); |
| 3802 | |||
| 3803 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (new_max_open_files < current_minimum_limit_for_open_files) { |
| 3804 | /* The limit was already exceeded while we were setting the | ||
| 3805 | m_open_files_limit.get_limit(). We rollback from the limit change. There is | ||
| 3806 | a counterpart check in the `Fil_shard::open_file` to rollback the limit | ||
| 3807 | reservation if this case is encountered there. */ | ||
| 3808 | ✗ | m_open_files_limit.revert_desired_limit(); | |
| 3809 | |||
| 3810 | /* Use the same value that was used for the check, to not mislead user with | ||
| 3811 | other value than was used in calculations. */ | ||
| 3812 | ✗ | new_max_open_files = current_minimum_limit_for_open_files; | |
| 3813 | ✗ | return false; | |
| 3814 | } | ||
| 3815 | |||
| 3816 | 12 | const auto set_new_limit_timeout = std::chrono::seconds(5); | |
| 3817 | |||
| 3818 | for (;;) { | ||
| 3819 | 37 | auto current_n_files_open = fil_n_files_open.load(); | |
| 3820 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 25 times.
|
37 | if ((size_t)new_max_open_files >= current_n_files_open) { |
| 3821 | 12 | break; | |
| 3822 | } | ||
| 3823 |
3/6✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 25 times.
|
25 | if (std::chrono::steady_clock::now() - start_time > set_new_limit_timeout) { |
| 3824 | /* Timeout, let's rollback the limit change and recommend a new limit. */ | ||
| 3825 | ✗ | m_open_files_limit.revert_desired_limit(); | |
| 3826 | |||
| 3827 | /* Use the same value that was used for the check, to not mislead user | ||
| 3828 | with other value than was used in calculations. */ | ||
| 3829 | ✗ | new_max_open_files = current_n_files_open; | |
| 3830 | ✗ | return false; | |
| 3831 | } | ||
| 3832 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | fil_system->flush_file_spaces(); |
| 3833 | |||
| 3834 |
2/4✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
|
25 | if (fil_system->close_file_in_all_LRU()) { |
| 3835 | /* We closed some file, loop again to re-evaluate situation. */ | ||
| 3836 | 25 | continue; | |
| 3837 | } | ||
| 3838 | ✗ | wait_while_ios_in_progress(); | |
| 3839 | 25 | } | |
| 3840 | |||
| 3841 | #ifndef UNIV_HOTBACKUP | ||
| 3842 | /* Set the new limit in system variable. */ | ||
| 3843 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | innobase_set_open_files_limit(new_max_open_files); |
| 3844 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | m_open_files_limit.commit_desired_limit(); |
| 3845 | #endif | ||
| 3846 | |||
| 3847 | 12 | return true; | |
| 3848 | } | ||
| 3849 | |||
| 3850 | /** Open all the system files. | ||
| 3851 | @param[in] max_n_open Maximum number of open files allowed | ||
| 3852 | @param[in,out] n_open Current number of open files */ | ||
| 3853 | 660688 | void Fil_shard::open_system_tablespaces(size_t max_n_open, size_t *n_open) { | |
| 3854 | 660688 | mutex_acquire(); | |
| 3855 | |||
| 3856 |
2/2✓ Branch 0 taken 9997 times.
✓ Branch 1 taken 660688 times.
|
670685 | for (auto elem : m_spaces) { |
| 3857 | 9997 | auto space = elem.second; | |
| 3858 | |||
| 3859 |
3/4✓ Branch 0 taken 9997 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 299 times.
✓ Branch 3 taken 9698 times.
|
9997 | if (Fil_system::space_belongs_in_LRU(space)) { |
| 3860 | 299 | continue; | |
| 3861 | } | ||
| 3862 | |||
| 3863 |
2/2✓ Branch 0 taken 9723 times.
✓ Branch 1 taken 9698 times.
|
19421 | for (auto &file : space->files) { |
| 3864 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 9699 times.
|
9723 | if (!file.is_open) { |
| 3865 |
2/4✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
|
24 | if (!open_file(&file)) { |
| 3866 | /* This func is called during server's startup. If some file of log | ||
| 3867 | or system tablespace is missing, the server can't start | ||
| 3868 | successfully. So we should assert for it. */ | ||
| 3869 | ✗ | ut_error; | |
| 3870 | } | ||
| 3871 | |||
| 3872 | 24 | ++*n_open; | |
| 3873 | } | ||
| 3874 | |||
| 3875 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9723 times.
|
9723 | if (max_n_open < 10 + *n_open) { |
| 3876 | ✗ | ib::warn(ER_IB_MSG_284, *n_open, max_n_open); | |
| 3877 | } | ||
| 3878 | } | ||
| 3879 | } | ||
| 3880 | |||
| 3881 | 660688 | mutex_release(); | |
| 3882 | 660688 | } | |
| 3883 | |||
| 3884 | /** Opens all system tablespace data files in all shards. */ | ||
| 3885 | 9716 | void Fil_system::open_all_system_tablespaces() { | |
| 3886 | 9716 | size_t n_open = 0; | |
| 3887 | |||
| 3888 |
2/2✓ Branch 0 taken 660688 times.
✓ Branch 1 taken 9716 times.
|
670404 | for (auto shard : m_shards) { |
| 3889 |
1/2✓ Branch 0 taken 660688 times.
✗ Branch 1 not taken.
|
660688 | shard->open_system_tablespaces(get_open_files_limit(), &n_open); |
| 3890 | } | ||
| 3891 | 9716 | } | |
| 3892 | |||
| 3893 | /** Opens all system tablespace data files. They stay open until the | ||
| 3894 | database server shutdown. This should be called at a server startup | ||
| 3895 | after the space objects for the log and the system tablespace have | ||
| 3896 | been created. The purpose of this operation is to make sure we never | ||
| 3897 | run out of file descriptors if we need to read from the insert buffer | ||
| 3898 | or to write to the log. */ | ||
| 3899 | 9716 | void fil_open_system_tablespace_files() { | |
| 3900 | 9716 | fil_system->open_all_system_tablespaces(); | |
| 3901 | 9716 | } | |
| 3902 | |||
| 3903 | #ifndef UNIV_HOTBACKUP | ||
| 3904 | #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG | ||
| 3905 | 2873 | static void fil_validate_space_reference_count( | |
| 3906 | fil_space_t *space, Space_References &buffer_pool_references) { | ||
| 3907 |
1/2✓ Branch 0 taken 2873 times.
✗ Branch 1 not taken.
|
2873 | const auto space_reference_count = space->get_reference_count(); |
| 3908 | |||
| 3909 |
2/4✓ Branch 0 taken 2873 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2873 times.
|
2873 | if (space_reference_count != buffer_pool_references[space]) { |
| 3910 | ✗ | ib::error() << "Space id=" << space->id << " reference count is " | |
| 3911 | ✗ | << space_reference_count | |
| 3912 | ✗ | << ", while references count found in buffer pool is " | |
| 3913 | ✗ | << buffer_pool_references[space] << ". fast_shutdown is " | |
| 3914 | ✗ | << srv_fast_shutdown; | |
| 3915 | } | ||
| 3916 | 2873 | } | |
| 3917 | |||
| 3918 | 14008 | void Fil_shard::validate_space_reference_count( | |
| 3919 | Space_References &buffer_pool_references) { | ||
| 3920 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14008 times.
|
14008 | ut_ad(!mutex_owned()); |
| 3921 | |||
| 3922 | 14008 | mutex_acquire(); | |
| 3923 | |||
| 3924 |
2/2✓ Branch 0 taken 2827 times.
✓ Branch 1 taken 14008 times.
|
16835 | for (auto &e : m_spaces) { |
| 3925 |
1/2✓ Branch 0 taken 2827 times.
✗ Branch 1 not taken.
|
2827 | fil_validate_space_reference_count(e.second, buffer_pool_references); |
| 3926 | } | ||
| 3927 | |||
| 3928 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 14008 times.
|
14054 | for (auto &e : m_deleted_spaces) { |
| 3929 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | fil_validate_space_reference_count(e.second, buffer_pool_references); |
| 3930 | } | ||
| 3931 | |||
| 3932 | 14008 | mutex_release(); | |
| 3933 | 14008 | } | |
| 3934 | #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ | ||
| 3935 | #endif /* !UNIV_HOTBACKUP */ | ||
| 3936 | |||
| 3937 | 569772 | void Fil_shard::close_all_files() { | |
| 3938 |
2/4✓ Branch 0 taken 569772 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 569772 times.
|
569772 | ut_ad(mutex_owned()); |
| 3939 | |||
| 3940 | /* Iterates over a specified container of pair */ | ||
| 3941 | 2279092 | auto iterate_all_spaces_files = [this](auto &spaces, auto preprocess_space, | |
| 3942 | 140956 | auto postprocess_space) { | |
| 3943 |
2/2✓ Branch 0 taken 178580 times.
✓ Branch 1 taken 1139544 times.
|
2636248 | for (auto &e : spaces) { |
| 3944 | 357160 | auto &space = e.second; | |
| 3945 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 178580 times.
|
357160 | if (space == nullptr) { |
| 3946 | ✗ | continue; | |
| 3947 | } | ||
| 3948 | |||
| 3949 |
1/2✓ Branch 0 taken 178580 times.
✗ Branch 1 not taken.
|
357160 | preprocess_space(space); |
| 3950 | |||
| 3951 |
2/2✓ Branch 0 taken 178608 times.
✓ Branch 1 taken 178578 times.
|
714372 | for (auto &file : space->files) { |
| 3952 |
7/8✓ Branch 0 taken 70476 times.
✓ Branch 1 taken 108132 times.
✓ Branch 2 taken 70476 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 70474 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 178606 times.
|
357216 | if (file.is_open && !file.can_be_closed()) { |
| 3953 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | mutex_release(); |
| 3954 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | std::this_thread::sleep_for(std::chrono::milliseconds{1}); |
| 3955 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | mutex_acquire(); |
| 3956 | /* Files or spaces could have changed when we did not hold the | ||
| 3957 | mutex, restart the loop. */ | ||
| 3958 | 4 | return false; | |
| 3959 | } | ||
| 3960 |
2/2✓ Branch 0 taken 70474 times.
✓ Branch 1 taken 108132 times.
|
357212 | if (file.is_open) { |
| 3961 |
1/2✓ Branch 0 taken 70474 times.
✗ Branch 1 not taken.
|
140948 | close_file(&file); |
| 3962 | } | ||
| 3963 | } | ||
| 3964 | |||
| 3965 |
1/2✓ Branch 0 taken 174465 times.
✗ Branch 1 not taken.
|
357156 | postprocess_space(space); |
| 3966 | |||
| 3967 |
1/2✓ Branch 0 taken 178578 times.
✗ Branch 1 not taken.
|
357156 | space_free_low(space); |
| 3968 | |||
| 3969 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 178578 times.
|
357156 | ut_a(space == nullptr); |
| 3970 | } | ||
| 3971 | 2279088 | return true; | |
| 3972 | 569772 | }; | |
| 3973 | |||
| 3974 | for (;;) { | ||
| 3975 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 569772 times.
|
569774 | if (!iterate_all_spaces_files( |
| 3976 |
1/2✓ Branch 0 taken 569774 times.
✗ Branch 1 not taken.
|
569774 | m_spaces, |
| 3977 | 174467 | [](auto space) { | |
| 3978 |
6/8✓ Branch 0 taken 166198 times.
✓ Branch 1 taken 8269 times.
✓ Branch 2 taken 74791 times.
✓ Branch 3 taken 91407 times.
✓ Branch 4 taken 74791 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 174467 times.
|
174467 | ut_a(space->id == TRX_SYS_SPACE || |
| 3979 | space->purpose == FIL_TYPE_TEMPORARY || | ||
| 3980 | space->files.size() == 1); | ||
| 3981 | 174467 | }, | |
| 3982 | 174465 | [this](auto space) { space_detach(space); })) { | |
| 3983 | 2 | continue; | |
| 3984 | } | ||
| 3985 | |||
| 3986 | 569772 | m_spaces.clear(); | |
| 3987 | |||
| 3988 | #ifndef UNIV_HOTBACKUP | ||
| 3989 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 569772 times.
|
569772 | if (!iterate_all_spaces_files( |
| 3990 |
1/2✓ Branch 0 taken 569772 times.
✗ Branch 1 not taken.
|
569772 | m_deleted_spaces, |
| 3991 | 4113 | [](auto space) { | |
| 3992 |
3/6✓ Branch 0 taken 4113 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4113 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4113 times.
|
4113 | ut_a(space->id != TRX_SYS_SPACE && |
| 3993 | space->id != dict_sys_t::s_dict_space_id); | ||
| 3994 | |||
| 3995 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4113 times.
|
4113 | ut_a(space->files.size() <= 1); |
| 3996 | 4113 | }, | |
| 3997 | 4113 | [](auto) {})) { | |
| 3998 | ✗ | continue; | |
| 3999 | } | ||
| 4000 | |||
| 4001 | 569772 | m_deleted_spaces.clear(); | |
| 4002 | #endif /* !UNIV_HOTBACKUP */ | ||
| 4003 | 569772 | break; | |
| 4004 | 2 | } | |
| 4005 | 569772 | } | |
| 4006 | |||
| 4007 | /** Close all open files. */ | ||
| 4008 | 8379 | void Fil_system::close_all_files() { | |
| 4009 | #ifndef UNIV_HOTBACKUP | ||
| 4010 | #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG | ||
| 4011 | 8379 | bool should_validate_space_reference_count = srv_fast_shutdown == 0; | |
| 4012 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8379 times.
|
8379 | DBUG_EXECUTE_IF("buf_disable_space_reference_count_check", |
| 4013 | should_validate_space_reference_count = false;); | ||
| 4014 | |||
| 4015 |
2/2✓ Branch 0 taken 206 times.
✓ Branch 1 taken 8173 times.
|
8379 | if (should_validate_space_reference_count) { |
| 4016 |
1/2✓ Branch 0 taken 206 times.
✗ Branch 1 not taken.
|
206 | auto buffer_pool_references = buf_LRU_count_space_references(); |
| 4017 |
2/2✓ Branch 0 taken 14008 times.
✓ Branch 1 taken 206 times.
|
14214 | for (auto shard : m_shards) { |
| 4018 |
1/2✓ Branch 0 taken 14008 times.
✗ Branch 1 not taken.
|
14008 | shard->validate_space_reference_count(buffer_pool_references); |
| 4019 | } | ||
| 4020 | 206 | } | |
| 4021 | #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ | ||
| 4022 | #endif /* !UNIV_HOTBACKUP */ | ||
| 4023 | |||
| 4024 |
2/2✓ Branch 0 taken 569772 times.
✓ Branch 1 taken 8379 times.
|
578151 | for (auto shard : m_shards) { |
| 4025 |
1/2✓ Branch 0 taken 569772 times.
✗ Branch 1 not taken.
|
569772 | shard->mutex_acquire(); |
| 4026 | |||
| 4027 |
1/2✓ Branch 0 taken 569772 times.
✗ Branch 1 not taken.
|
569772 | shard->close_all_files(); |
| 4028 | |||
| 4029 |
1/2✓ Branch 0 taken 569772 times.
✗ Branch 1 not taken.
|
569772 | shard->mutex_release(); |
| 4030 | } | ||
| 4031 | |||
| 4032 | #ifndef UNIV_HOTBACKUP | ||
| 4033 | /* Revert to old names if downgrading after upgrade failure. */ | ||
| 4034 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 8349 times.
|
8379 | if (srv_downgrade_partition_files) { |
| 4035 | 30 | rename_partition_files(true); | |
| 4036 | } | ||
| 4037 | |||
| 4038 | 8379 | clear_old_files(); | |
| 4039 | #endif /* !UNIV_HOTBACKUP */ | ||
| 4040 | 8379 | } | |
| 4041 | |||
| 4042 | /** Closes all open files. There must not be any pending i/o's or not flushed | ||
| 4043 | modifications in the files. */ | ||
| 4044 | 8379 | void fil_close_all_files() { | |
| 4045 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8379 times.
|
8379 | if (!fil_system) return; |
| 4046 | |||
| 4047 | 8379 | fil_system->close_all_files(); | |
| 4048 | } | ||
| 4049 | |||
| 4050 | /** Iterate through all persistent tablespace files (FIL_TYPE_TABLESPACE) | ||
| 4051 | returning the nodes via callback function cbk. | ||
| 4052 | @param[in] f Callback | ||
| 4053 | @return any error returned by the callback function. */ | ||
| 4054 | 52360 | dberr_t Fil_shard::iterate(Fil_iterator::Function &f) { | |
| 4055 | 52360 | mutex_acquire(); | |
| 4056 | |||
| 4057 |
2/2✓ Branch 0 taken 19576 times.
✓ Branch 1 taken 52360 times.
|
71936 | for (auto &elem : m_spaces) { |
| 4058 | 19576 | auto space = elem.second; | |
| 4059 | |||
| 4060 |
2/2✓ Branch 0 taken 8470 times.
✓ Branch 1 taken 11106 times.
|
19576 | if (space->purpose != FIL_TYPE_TABLESPACE) { |
| 4061 | 8470 | continue; | |
| 4062 | } | ||
| 4063 | |||
| 4064 |
2/2✓ Branch 0 taken 11118 times.
✓ Branch 1 taken 11106 times.
|
22224 | for (auto &file : space->files) { |
| 4065 | /* Note: The callback can release the mutex. */ | ||
| 4066 | |||
| 4067 |
1/2✓ Branch 0 taken 11118 times.
✗ Branch 1 not taken.
|
11118 | dberr_t err = f(&file); |
| 4068 | |||
| 4069 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11118 times.
|
11118 | if (err != DB_SUCCESS) { |
| 4070 | ✗ | mutex_release(); | |
| 4071 | |||
| 4072 | ✗ | return err; | |
| 4073 | } | ||
| 4074 | } | ||
| 4075 | } | ||
| 4076 | |||
| 4077 | 52360 | mutex_release(); | |
| 4078 | |||
| 4079 | 52360 | return DB_SUCCESS; | |
| 4080 | } | ||
| 4081 | |||
| 4082 | 770 | dberr_t Fil_system::iterate(Fil_iterator::Function &f) { | |
| 4083 |
2/2✓ Branch 0 taken 52360 times.
✓ Branch 1 taken 770 times.
|
53130 | for (auto shard : m_shards) { |
| 4084 |
1/2✓ Branch 0 taken 52360 times.
✗ Branch 1 not taken.
|
52360 | dberr_t err = shard->iterate(f); |
| 4085 | |||
| 4086 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52360 times.
|
52360 | if (err != DB_SUCCESS) { |
| 4087 | ✗ | return err; | |
| 4088 | } | ||
| 4089 | } | ||
| 4090 | |||
| 4091 | 770 | return DB_SUCCESS; | |
| 4092 | } | ||
| 4093 | |||
| 4094 | 770 | dberr_t Fil_iterator::iterate(Function &&f) { return fil_system->iterate(f); } | |
| 4095 | |||
| 4096 | /** Sets the max tablespace id counter if the given number is bigger than the | ||
| 4097 | previous value. | ||
| 4098 | @param[in] max_id Maximum known tablespace ID */ | ||
| 4099 | 28614 | void fil_set_max_space_id_if_bigger(space_id_t max_id) { | |
| 4100 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28614 times.
|
28614 | if (dict_sys_t::is_reserved(max_id)) { |
| 4101 | ✗ | ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_285, ulong{max_id}); | |
| 4102 | } | ||
| 4103 | |||
| 4104 | 28614 | fil_system->update_maximum_space_id(max_id); | |
| 4105 | 28614 | } | |
| 4106 | |||
| 4107 | /** Write the flushed LSN to the page header of the first page in the | ||
| 4108 | system tablespace. | ||
| 4109 | @param[in] lsn Flushed LSN | ||
| 4110 | @return DB_SUCCESS or error number */ | ||
| 4111 | 8663 | dberr_t fil_write_flushed_lsn(lsn_t lsn) { | |
| 4112 | dberr_t err; | ||
| 4113 | |||
| 4114 | auto buf = | ||
| 4115 | 8663 | static_cast<byte *>(ut::aligned_alloc(UNIV_PAGE_SIZE, UNIV_PAGE_SIZE)); | |
| 4116 | |||
| 4117 | 8663 | const page_id_t page_id(TRX_SYS_SPACE, 0); | |
| 4118 | |||
| 4119 |
2/4✓ Branch 0 taken 8663 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8663 times.
✗ Branch 3 not taken.
|
8663 | err = fil_read(page_id, univ_page_size, 0, univ_page_size.physical(), buf); |
| 4120 | |||
| 4121 |
1/2✓ Branch 0 taken 8663 times.
✗ Branch 1 not taken.
|
8663 | if (err == DB_SUCCESS) { |
| 4122 |
1/2✓ Branch 0 taken 8663 times.
✗ Branch 1 not taken.
|
8663 | mach_write_to_8(buf + FIL_PAGE_FILE_FLUSH_LSN, lsn); |
| 4123 | |||
| 4124 |
2/4✓ Branch 0 taken 8663 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8663 times.
✗ Branch 3 not taken.
|
8663 | err = fil_write(page_id, univ_page_size, 0, univ_page_size.physical(), buf); |
| 4125 | |||
| 4126 |
1/2✓ Branch 0 taken 8663 times.
✗ Branch 1 not taken.
|
8663 | fil_system->flush_file_spaces(); |
| 4127 | } | ||
| 4128 | |||
| 4129 | 8663 | ut::aligned_free(buf); | |
| 4130 | |||
| 4131 | 8663 | return err; | |
| 4132 | } | ||
| 4133 | |||
| 4134 | /** Acquire a tablespace when it could be dropped concurrently. | ||
| 4135 | Used by background threads that do not necessarily hold proper locks | ||
| 4136 | for concurrency control. | ||
| 4137 | @param[in] space_id Tablespace ID | ||
| 4138 | @param[in] silent Whether to silently ignore missing tablespaces | ||
| 4139 | @return the tablespace, or nullptr if missing or being deleted */ | ||
| 4140 | 30004423 | fil_space_t *Fil_system::space_acquire(space_id_t space_id, bool silent) { | |
| 4141 | 30004423 | auto shard = fil_system->shard_by_id(space_id); | |
| 4142 | |||
| 4143 | 30006077 | shard->mutex_acquire(); | |
| 4144 | |||
| 4145 | 30007420 | fil_space_t *space = shard->get_space_by_id(space_id); | |
| 4146 | |||
| 4147 |
2/2✓ Branch 0 taken 16413 times.
✓ Branch 1 taken 29991009 times.
|
30007422 | if (space == nullptr) { |
| 4148 |
6/6✓ Branch 0 taken 67 times.
✓ Branch 1 taken 16346 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 16406 times.
|
16413 | if (!silent && m_ACCESSING_NONEXISTINC_SPACE_throttler.apply()) { |
| 4149 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | ib::warn(ER_IB_WARN_ACCESSING_NONEXISTINC_SPACE, ulong{space_id}); |
| 4150 | } | ||
| 4151 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29991015 times.
|
29991009 | } else if (!shard->space_acquire(space)) { |
| 4152 | ✗ | space = nullptr; | |
| 4153 | } | ||
| 4154 | |||
| 4155 | 30007428 | shard->mutex_release(); | |
| 4156 | |||
| 4157 | 30007512 | return space; | |
| 4158 | } | ||
| 4159 | |||
| 4160 | 29990887 | inline bool Fil_shard::space_acquire(fil_space_t *space) { | |
| 4161 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29990991 times.
|
29990887 | ut_ad(mutex_owned()); |
| 4162 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29991026 times.
|
29990991 | ut_ad(space != nullptr); |
| 4163 | |||
| 4164 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29991026 times.
|
29991026 | if (space->stop_new_ops) { |
| 4165 | ✗ | return false; | |
| 4166 | } | ||
| 4167 | |||
| 4168 | 29991026 | ++space->n_pending_ops; | |
| 4169 | |||
| 4170 | 29991026 | return true; | |
| 4171 | } | ||
| 4172 | |||
| 4173 | /** Acquire a tablespace when it could be dropped concurrently. | ||
| 4174 | Used by background threads that do not necessarily hold proper locks | ||
| 4175 | for concurrency control. | ||
| 4176 | @param[in] space_id Tablespace ID | ||
| 4177 | @return the tablespace, or nullptr if missing or being deleted */ | ||
| 4178 | 1129809 | fil_space_t *fil_space_acquire(space_id_t space_id) { | |
| 4179 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1129809 times.
|
1129809 | if (!fil_system) return nullptr; |
| 4180 | 1129809 | return fil_system->space_acquire(space_id, false); | |
| 4181 | } | ||
| 4182 | |||
| 4183 | /** Acquire a tablespace that may not exist. | ||
| 4184 | Used by background threads that do not necessarily hold proper locks | ||
| 4185 | for concurrency control. | ||
| 4186 | @param[in] space_id Tablespace ID | ||
| 4187 | @return the tablespace, or nullptr if missing or being deleted */ | ||
| 4188 | 28874766 | fil_space_t *fil_space_acquire_silent(space_id_t space_id) { | |
| 4189 | 28874766 | return fil_system->space_acquire(space_id, true); | |
| 4190 | } | ||
| 4191 | |||
| 4192 | /** Release a tablespace acquired with fil_space_acquire(). | ||
| 4193 | @param[in,out] space Tablespace to release */ | ||
| 4194 | 29990817 | void fil_space_release(fil_space_t *space) { | |
| 4195 | 29990817 | auto shard = fil_system->shard_by_id(space->id); | |
| 4196 | |||
| 4197 | 29991071 | shard->mutex_acquire(); | |
| 4198 | 29991052 | shard->space_release(space); | |
| 4199 | 29990975 | shard->mutex_release(); | |
| 4200 | 29991096 | } | |
| 4201 | |||
| 4202 | /** Release a tablespace acquired with Fil_shard::space_acquire(). | ||
| 4203 | @param[in,out] space tablespace to release */ | ||
| 4204 | 29990930 | void Fil_shard::space_release(fil_space_t *space) { | |
| 4205 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29990974 times.
|
29990930 | ut_ad(space->magic_n == FIL_SPACE_MAGIC_N); |
| 4206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29990964 times.
|
29990974 | ut_ad(space->n_pending_ops > 0); |
| 4207 | |||
| 4208 | 29990964 | --space->n_pending_ops; | |
| 4209 | 29990964 | } | |
| 4210 | |||
| 4211 | /** Acquire a tablespace for reading or writing a block, | ||
| 4212 | when it could be dropped concurrently. | ||
| 4213 | @param[in] id tablespace ID | ||
| 4214 | @return the tablespace | ||
| 4215 | @retval NULL if missing */ | ||
| 4216 | 45206213 | fil_space_t *fil_space_acquire_for_io(space_id_t space_id) { | |
| 4217 | 45206213 | auto shard = fil_system->shard_by_id(space_id); | |
| 4218 | |||
| 4219 | 45206858 | shard->mutex_acquire(); | |
| 4220 | |||
| 4221 | 45207604 | fil_space_t *space = shard->get_space_by_id(space_id); | |
| 4222 | |||
| 4223 |
2/2✓ Branch 0 taken 45207569 times.
✓ Branch 1 taken 11 times.
|
45207580 | if (space) { |
| 4224 | 45207569 | space->n_pending_ios++; | |
| 4225 | } | ||
| 4226 | |||
| 4227 | 45207580 | shard->mutex_release(); | |
| 4228 | |||
| 4229 | 45207664 | return (space); | |
| 4230 | } | ||
| 4231 | |||
| 4232 | /** Acquire a tablespace for reading or writing a block, | ||
| 4233 | when it could be dropped concurrently. | ||
| 4234 | @param[in] id tablespace ID | ||
| 4235 | @return the tablespace | ||
| 4236 | @retval NULL if missing */ | ||
| 4237 | 273556 | fil_space_t *fil_space_acquire_for_io_with_load(space_id_t space_id) { | |
| 4238 | 273556 | auto shard = fil_system->shard_by_id(space_id); | |
| 4239 | |||
| 4240 | 273556 | shard->mutex_acquire(); | |
| 4241 | |||
| 4242 | 273556 | fil_space_t *space = shard->space_load(space_id); | |
| 4243 | |||
| 4244 |
1/2✓ Branch 0 taken 273556 times.
✗ Branch 1 not taken.
|
273556 | if (space) { |
| 4245 | 273556 | space->n_pending_ios++; | |
| 4246 | } | ||
| 4247 | |||
| 4248 | 273556 | shard->mutex_release(); | |
| 4249 | |||
| 4250 | 273556 | return (space); | |
| 4251 | } | ||
| 4252 | |||
| 4253 | /** Release a tablespace acquired with fil_space_acquire_for_io(). | ||
| 4254 | @param[in,out] space tablespace to release */ | ||
| 4255 | 45480184 | void fil_space_release_for_io(fil_space_t *space) { | |
| 4256 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45480526 times.
|
45480184 | ut_ad(space); |
| 4257 | 45480526 | auto shard = fil_system->shard_by_id(space->id); | |
| 4258 | |||
| 4259 | 45480606 | shard->mutex_acquire(); | |
| 4260 | |||
| 4261 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45481155 times.
|
45481141 | ut_ad(space->magic_n == FIL_SPACE_MAGIC_N); |
| 4262 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45481153 times.
|
45481155 | ut_ad(space->n_pending_ios > 0); |
| 4263 | |||
| 4264 | 45481153 | --space->n_pending_ios; | |
| 4265 | |||
| 4266 | 45481153 | shard->mutex_release(); | |
| 4267 | 45481186 | } | |
| 4268 | |||
| 4269 | 3544 | fil_space_t *fil_space_get_next_in_shard(fil_space_t *space, Fil_shard *shard) { | |
| 4270 |
2/2✓ Branch 0 taken 3130 times.
✓ Branch 1 taken 414 times.
|
3544 | space = (space == nullptr) ? UT_LIST_GET_FIRST(shard->m_space_list) |
| 4271 | : UT_LIST_GET_NEXT(space_list, space); | ||
| 4272 | /* Skip spaces that are being created by | ||
| 4273 | fil_ibd_create(), or dropped, or !tablespace. */ | ||
| 4274 |
6/8✓ Branch 0 taken 922 times.
✓ Branch 1 taken 3128 times.
✓ Branch 2 taken 922 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 922 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 506 times.
✓ Branch 7 taken 3544 times.
|
4972 | while (space != nullptr && (space->files.empty() || space->is_stopping() || |
| 4275 |
2/2✓ Branch 0 taken 506 times.
✓ Branch 1 taken 416 times.
|
922 | space->purpose != FIL_TYPE_TABLESPACE)) { |
| 4276 | 506 | space = UT_LIST_GET_NEXT(space_list, space); | |
| 4277 | } | ||
| 4278 | 3544 | return space; | |
| 4279 | } | ||
| 4280 | |||
| 4281 | /** | ||
| 4282 | Remove space from key rotation list if there are no more | ||
| 4283 | pending operations. | ||
| 4284 | @param[in] space Tablespace */ | ||
| 4285 | ✗ | static void fil_space_remove_from_keyrotation(Fil_shard *shard, | |
| 4286 | fil_space_t *space) { | ||
| 4287 | ✗ | ut_ad(shard->mutex_owned()); | |
| 4288 | ✗ | ut_ad(space); | |
| 4289 | |||
| 4290 | ✗ | if (space->n_pending_ops == 0 && space->is_in_rotation_list) { | |
| 4291 | ✗ | space->is_in_rotation_list = false; | |
| 4292 | ✗ | ut_a(UT_LIST_GET_LEN(shard->m_rotation_list) > 0); | |
| 4293 | ✗ | UT_LIST_REMOVE(shard->m_rotation_list, space); | |
| 4294 | } | ||
| 4295 | } | ||
| 4296 | |||
| 4297 | ✗ | fil_space_t *fil_space_get_next_in_shards_rotation_list(fil_space_t *space, | |
| 4298 | Fil_shard *shard) { | ||
| 4299 | ✗ | if (space == nullptr) { | |
| 4300 | ✗ | space = UT_LIST_GET_FIRST(shard->m_rotation_list); | |
| 4301 | } else { | ||
| 4302 | ✗ | fil_space_t *prev_space = space; | |
| 4303 | ✗ | space = UT_LIST_GET_NEXT(rotation_list, prev_space); | |
| 4304 | ✗ | fil_space_remove_from_keyrotation(shard, prev_space); | |
| 4305 | } | ||
| 4306 | /* Skip spaces that are being created by | ||
| 4307 | fil_ibd_create(), or dropped, or !tablespace. */ | ||
| 4308 | ✗ | while (space != nullptr && (space->files.empty() || space->is_stopping() || | |
| 4309 | ✗ | space->purpose != FIL_TYPE_TABLESPACE)) { | |
| 4310 | ✗ | fil_space_t *prev_space = space; | |
| 4311 | ✗ | space = UT_LIST_GET_NEXT(rotation_list, prev_space); | |
| 4312 | ✗ | fil_space_remove_from_keyrotation(shard, prev_space); | |
| 4313 | } | ||
| 4314 | ✗ | return space; | |
| 4315 | } | ||
| 4316 | |||
| 4317 | /** Return the next fil_space_t. | ||
| 4318 | Once started, the caller must keep calling this until it returns NULL. | ||
| 4319 | fil_space_acquire() and fil_space_t::release() are invoked here which | ||
| 4320 | blocks a concurrent operation from dropping the tablespace. | ||
| 4321 | @param[in] prev_space Pointer to the previous fil_space_t. | ||
| 4322 | If NULL, use the first fil_space_t on fil_system.space_list. | ||
| 4323 | @return pointer to the next fil_space_t. | ||
| 4324 | @retval NULL if this was the last*/ | ||
| 4325 | 462 | fil_space_t *fil_space_next( | |
| 4326 | fil_space_t *prev_space) // TODO: It should be a part of Fil_system | ||
| 4327 | { | ||
| 4328 | 462 | fil_space_t *space = prev_space; | |
| 4329 | |||
| 4330 |
1/2✓ Branch 0 taken 462 times.
✗ Branch 1 not taken.
|
462 | mutex_enter(&fil_crypt_list_mutex); |
| 4331 | |||
| 4332 | 462 | Fil_shard *shard = nullptr; | |
| 4333 | 462 | uint shard_index = 0; | |
| 4334 | |||
| 4335 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 414 times.
|
462 | if (prev_space == nullptr) { |
| 4336 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | shard = fil_system->shard_by_index(shard_index); |
| 4337 | |||
| 4338 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | shard->mutex_acquire(); |
| 4339 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | space = fil_space_get_next_in_shard(prev_space, shard); |
| 4340 | } | ||
| 4341 | |||
| 4342 |
2/2✓ Branch 0 taken 414 times.
✓ Branch 1 taken 48 times.
|
462 | if (prev_space != nullptr) { |
| 4343 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 414 times.
|
414 | ut_ad(space->n_pending_ops > |
| 4344 | 0); // we are sure that space exists as space | ||
| 4345 | // with n_pending_ops > 0 cannot be removed | ||
| 4346 |
1/2✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
|
414 | shard = fil_system->shard_by_id(space->id, &shard_index); |
| 4347 |
1/2✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
|
414 | shard->mutex_acquire(); |
| 4348 | |||
| 4349 | /* Move on to the next fil_space_t */ | ||
| 4350 | 414 | space->n_pending_ops--; | |
| 4351 |
1/2✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
|
414 | space = fil_space_get_next_in_shard(space, shard); |
| 4352 | } | ||
| 4353 | |||
| 4354 |
6/6✓ Branch 0 taken 3128 times.
✓ Branch 1 taken 416 times.
✓ Branch 2 taken 3082 times.
✓ Branch 3 taken 46 times.
✓ Branch 4 taken 3082 times.
✓ Branch 5 taken 462 times.
|
6672 | while (space == nullptr && |
| 4355 | 3128 | (++shard_index < fil_system->get_number_of_shards())) { | |
| 4356 |
1/2✓ Branch 0 taken 3082 times.
✗ Branch 1 not taken.
|
3082 | shard->mutex_release(); |
| 4357 |
1/2✓ Branch 0 taken 3082 times.
✗ Branch 1 not taken.
|
3082 | shard = fil_system->shard_by_index(shard_index); |
| 4358 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3082 times.
|
3082 | ut_ad(shard != nullptr); |
| 4359 |
1/2✓ Branch 0 taken 3082 times.
✗ Branch 1 not taken.
|
3082 | shard->mutex_acquire(); |
| 4360 |
1/2✓ Branch 0 taken 3082 times.
✗ Branch 1 not taken.
|
3082 | space = fil_space_get_next_in_shard(space, shard); |
| 4361 | } | ||
| 4362 | |||
| 4363 |
2/2✓ Branch 0 taken 416 times.
✓ Branch 1 taken 46 times.
|
462 | if (space != nullptr) { |
| 4364 | 416 | space->n_pending_ops++; | |
| 4365 | } | ||
| 4366 | |||
| 4367 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 462 times.
|
462 | ut_ad(shard != nullptr); |
| 4368 |
1/2✓ Branch 0 taken 462 times.
✗ Branch 1 not taken.
|
462 | shard->mutex_release(); |
| 4369 |
1/2✓ Branch 0 taken 462 times.
✗ Branch 1 not taken.
|
462 | mutex_exit(&fil_crypt_list_mutex); |
| 4370 | |||
| 4371 | 462 | return (space); | |
| 4372 | } | ||
| 4373 | |||
| 4374 | /** Return the next fil_space_t from key rotation list. | ||
| 4375 | Once started, the caller must keep calling this until it returns NULL. | ||
| 4376 | fil_space_acquire() and fil_space_release() are invoked here which | ||
| 4377 | blocks a concurrent operation from dropping the tablespace. | ||
| 4378 | @param[in] prev_space Pointer to the previous fil_space_t. | ||
| 4379 | If NULL, use the first fil_space_t on fil_system->space_list. | ||
| 4380 | @return pointer to the next fil_space_t. | ||
| 4381 | @retval NULL if this was the last*/ | ||
| 4382 | ✗ | fil_space_t *fil_space_keyrotate_next( | |
| 4383 | fil_space_t *prev_space) { // TODO: To powinno być częścią Fil_system | ||
| 4384 | |||
| 4385 | ✗ | fil_space_t *space = prev_space; | |
| 4386 | ✗ | mutex_enter(&fil_crypt_list_mutex); | |
| 4387 | |||
| 4388 | ✗ | Fil_shard *shard = nullptr; | |
| 4389 | ✗ | uint shard_index = 0; | |
| 4390 | |||
| 4391 | ✗ | if (prev_space == nullptr) { | |
| 4392 | ✗ | shard = fil_system->shard_by_index(shard_index); | |
| 4393 | |||
| 4394 | ✗ | shard->mutex_acquire(); | |
| 4395 | ✗ | space = fil_space_get_next_in_shards_rotation_list(prev_space, shard); | |
| 4396 | } | ||
| 4397 | |||
| 4398 | ✗ | if (prev_space != NULL) { | |
| 4399 | ✗ | ut_ad(space->n_pending_ops > | |
| 4400 | 0); // we are sure that space exists as space | ||
| 4401 | // with n_pending_ops > 0 cannot be removed | ||
| 4402 | ✗ | uint shard_index = 0; | |
| 4403 | ✗ | shard = fil_system->shard_by_id(space->id, &shard_index); | |
| 4404 | ✗ | shard->mutex_acquire(); | |
| 4405 | /* Move on to the next fil_space_t */ | ||
| 4406 | ✗ | space->n_pending_ops--; | |
| 4407 | ✗ | space = fil_space_get_next_in_shards_rotation_list(prev_space, shard); | |
| 4408 | } | ||
| 4409 | |||
| 4410 | ✗ | while (space == nullptr && | |
| 4411 | ✗ | (++shard_index < fil_system->get_number_of_shards())) { | |
| 4412 | ✗ | shard->mutex_release(); | |
| 4413 | ✗ | shard = fil_system->shard_by_index(shard_index); | |
| 4414 | ✗ | ut_ad(shard != nullptr); | |
| 4415 | ✗ | shard->mutex_acquire(); | |
| 4416 | ✗ | space = fil_space_get_next_in_shards_rotation_list(space, shard); | |
| 4417 | } | ||
| 4418 | |||
| 4419 | ✗ | if (space != nullptr) { | |
| 4420 | ✗ | space->n_pending_ops++; | |
| 4421 | } | ||
| 4422 | |||
| 4423 | ✗ | ut_ad(shard != nullptr); | |
| 4424 | ✗ | shard->mutex_release(); | |
| 4425 | ✗ | mutex_exit(&fil_crypt_list_mutex); | |
| 4426 | |||
| 4427 | ✗ | return space; | |
| 4428 | } | ||
| 4429 | |||
| 4430 | /** Check for pending operations. | ||
| 4431 | @param[in] space tablespace | ||
| 4432 | @param[in] count number of attempts so far | ||
| 4433 | @return 0 if no pending operations else count + 1. */ | ||
| 4434 | 267044 | ulint Fil_shard::space_check_pending_operations(fil_space_t *space, | |
| 4435 | ulint count) const { | ||
| 4436 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 267044 times.
|
267044 | ut_ad(mutex_owned()); |
| 4437 | |||
| 4438 |
3/4✓ Branch 0 taken 266881 times.
✓ Branch 1 taken 163 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 266881 times.
|
267044 | if (space != nullptr && space->n_pending_ops > 0) { |
| 4439 | ✗ | if (count > 5000) { | |
| 4440 | ✗ | ib::warn(ER_IB_MSG_287, space->name, ulong{space->n_pending_ops}); | |
| 4441 | } | ||
| 4442 | |||
| 4443 | ✗ | return count + 1; | |
| 4444 | } | ||
| 4445 | |||
| 4446 | 267044 | return 0; | |
| 4447 | } | ||
| 4448 | |||
| 4449 | /** Check for pending IO. | ||
| 4450 | @param[in] space Tablespace to check | ||
| 4451 | @param[in] file File in space list | ||
| 4452 | @param[in] count number of attempts so far | ||
| 4453 | @return 0 if no pending else count + 1. */ | ||
| 4454 | 267398 | ulint Fil_shard::check_pending_io(const fil_space_t *space, | |
| 4455 | const fil_node_t &file, ulint count) const { | ||
| 4456 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 267398 times.
|
267398 | ut_ad(mutex_owned()); |
| 4457 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 267398 times.
|
267398 | ut_a(space->n_pending_ops == 0); |
| 4458 | |||
| 4459 |
5/8✓ Branch 0 taken 267398 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 188010 times.
✓ Branch 3 taken 79388 times.
✓ Branch 4 taken 188010 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 267398 times.
|
267398 | ut_a(space->id == TRX_SYS_SPACE || space->purpose == FIL_TYPE_TEMPORARY || |
| 4460 | space->files.size() == 1); | ||
| 4461 | |||
| 4462 |
4/4✓ Branch 0 taken 266972 times.
✓ Branch 1 taken 426 times.
✓ Branch 2 taken 91 times.
✓ Branch 3 taken 266881 times.
|
267398 | if (space->n_pending_flushes > 0 || file.n_pending_ios > 0) { |
| 4463 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 517 times.
|
517 | if (count > 1000) { |
| 4464 | ✗ | ib::warn(ER_IB_MSG_288, space->name, ulong{space->n_pending_flushes}, | |
| 4465 | ✗ | size_t{file.n_pending_ios}); | |
| 4466 | } | ||
| 4467 | |||
| 4468 | 517 | return count + 1; | |
| 4469 | } | ||
| 4470 | |||
| 4471 | 266881 | return 0; | |
| 4472 | } | ||
| 4473 | |||
| 4474 | 267044 | dberr_t Fil_shard::wait_for_pending_operations(space_id_t space_id, | |
| 4475 | fil_space_t *&space, | ||
| 4476 | char **path) const { | ||
| 4477 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 267044 times.
|
267044 | ut_ad(!fsp_is_system_tablespace(space_id)); |
| 4478 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 267044 times.
|
267044 | ut_ad(!fsp_is_global_temporary(space_id)); |
| 4479 | |||
| 4480 | 267044 | space = nullptr; | |
| 4481 | |||
| 4482 | 267044 | mutex_acquire(); | |
| 4483 | |||
| 4484 | 267044 | fil_space_t *sp = get_space_by_id(space_id); | |
| 4485 | |||
| 4486 |
2/2✓ Branch 0 taken 266881 times.
✓ Branch 1 taken 163 times.
|
267044 | if (sp != nullptr) { |
| 4487 | 266881 | sp->stop_new_ops = true; | |
| 4488 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 266871 times.
|
266881 | if (sp->crypt_data) { |
| 4489 | 10 | sp->n_pending_ops++; | |
| 4490 | 10 | mutex_release(); | |
| 4491 | 10 | fil_space_crypt_close_tablespace(sp); | |
| 4492 | 10 | mutex_acquire(); | |
| 4493 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | ut_ad(sp->n_pending_ops > 0); |
| 4494 | 10 | sp->n_pending_ops--; | |
| 4495 | } | ||
| 4496 | } | ||
| 4497 | |||
| 4498 | /* Check for pending operations. */ | ||
| 4499 | |||
| 4500 | 267044 | ulint count = 0; | |
| 4501 | |||
| 4502 | do { | ||
| 4503 | 267044 | sp = get_space_by_id(space_id); | |
| 4504 | |||
| 4505 | 267044 | count = space_check_pending_operations(sp, count); | |
| 4506 | |||
| 4507 | 267044 | mutex_release(); | |
| 4508 | |||
| 4509 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 267044 times.
|
267044 | if (count > 0) { |
| 4510 | ✗ | std::this_thread::sleep_for(std::chrono::milliseconds(20)); | |
| 4511 | } | ||
| 4512 | |||
| 4513 | 267044 | mutex_acquire(); | |
| 4514 | |||
| 4515 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 267044 times.
|
267044 | } while (count > 0); |
| 4516 | |||
| 4517 | /* Check for pending IO. */ | ||
| 4518 | |||
| 4519 | 267044 | *path = nullptr; | |
| 4520 | |||
| 4521 | do { | ||
| 4522 | 267561 | sp = get_space_by_id(space_id); | |
| 4523 | |||
| 4524 |
2/2✓ Branch 0 taken 163 times.
✓ Branch 1 taken 267398 times.
|
267561 | if (sp == nullptr) { |
| 4525 | 163 | mutex_release(); | |
| 4526 | |||
| 4527 | 163 | return DB_TABLESPACE_NOT_FOUND; | |
| 4528 | } | ||
| 4529 | |||
| 4530 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 267398 times.
|
267398 | ut_a(sp->files.size() == 1); |
| 4531 | 267398 | const fil_node_t &file = sp->files.front(); | |
| 4532 | |||
| 4533 | 267398 | count = check_pending_io(sp, file, count); | |
| 4534 | |||
| 4535 |
2/2✓ Branch 0 taken 266881 times.
✓ Branch 1 taken 517 times.
|
267398 | if (count == 0) { |
| 4536 | 266881 | *path = mem_strdup(file.name); | |
| 4537 | } | ||
| 4538 | |||
| 4539 | 267398 | mutex_release(); | |
| 4540 | |||
| 4541 |
2/2✓ Branch 0 taken 266881 times.
✓ Branch 1 taken 517 times.
|
267398 | if (count == 0) { |
| 4542 | 266881 | break; | |
| 4543 | } | ||
| 4544 | |||
| 4545 |
1/2✓ Branch 0 taken 517 times.
✗ Branch 1 not taken.
|
517 | std::this_thread::sleep_for(std::chrono::milliseconds(20)); |
| 4546 | 517 | mutex_acquire(); | |
| 4547 | |||
| 4548 |
1/2✓ Branch 0 taken 517 times.
✗ Branch 1 not taken.
|
517 | } while (count > 0); |
| 4549 | |||
| 4550 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 266881 times.
|
266881 | ut_ad(sp != nullptr); |
| 4551 | |||
| 4552 | 266881 | space = sp; | |
| 4553 | |||
| 4554 | 266881 | return DB_SUCCESS; | |
| 4555 | } | ||
| 4556 | |||
| 4557 | 2912 | std::string Fil_path::get_existing_path(const std::string &path, | |
| 4558 | std::string &ghost) { | ||
| 4559 | 2912 | std::string existing_path{path}; | |
| 4560 | |||
| 4561 | /* This is only called for non-existing paths. */ | ||
| 4562 |
3/4✓ Branch 0 taken 6599 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3687 times.
✓ Branch 3 taken 2912 times.
|
6599 | while (!os_file_exists(existing_path.c_str())) { |
| 4563 | /* Some part of this path does not exist. | ||
| 4564 | If the last char is a separator, strip it off. */ | ||
| 4565 |
1/2✓ Branch 0 taken 3687 times.
✗ Branch 1 not taken.
|
3687 | trim_separator(existing_path); |
| 4566 | |||
| 4567 | 3687 | auto sep = existing_path.find_last_of(SEPARATOR); | |
| 4568 |
2/2✓ Branch 0 taken 1260 times.
✓ Branch 1 taken 2427 times.
|
3687 | if (sep == std::string::npos) { |
| 4569 | /* If no separator is found, it must be relative to the current dir. */ | ||
| 4570 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1260 times.
|
1260 | if (existing_path == ".") { |
| 4571 | /* This probably cannot happen, but break here to ensure that the | ||
| 4572 | loop always has a way out. */ | ||
| 4573 | ✗ | break; | |
| 4574 | } | ||
| 4575 |
1/2✓ Branch 0 taken 1260 times.
✗ Branch 1 not taken.
|
1260 | ghost.assign(path); |
| 4576 |
1/2✓ Branch 0 taken 1260 times.
✗ Branch 1 not taken.
|
1260 | existing_path.assign("."); |
| 4577 |
1/2✓ Branch 0 taken 1260 times.
✗ Branch 1 not taken.
|
1260 | existing_path.push_back(OS_SEPARATOR); |
| 4578 | } else { | ||
| 4579 |
1/2✓ Branch 0 taken 2427 times.
✗ Branch 1 not taken.
|
2427 | ghost.assign(path.substr(sep + 1, path.length())); |
| 4580 |
1/2✓ Branch 0 taken 2427 times.
✗ Branch 1 not taken.
|
2427 | existing_path.resize(sep + 1); |
| 4581 | } | ||
| 4582 | } | ||
| 4583 | |||
| 4584 | 2912 | return existing_path; | |
| 4585 | } | ||
| 4586 | |||
| 4587 | 871344 | std::string Fil_path::get_real_path(const std::string &path, bool force) { | |
| 4588 | bool path_exists; | ||
| 4589 | os_file_type_t path_type; | ||
| 4590 | char abspath[OS_FILE_MAX_PATH]; | ||
| 4591 |
1/2✓ Branch 0 taken 871344 times.
✗ Branch 1 not taken.
|
871344 | std::string in_path{path}; |
| 4592 | 871344 | std::string real_path; | |
| 4593 | |||
| 4594 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 871343 times.
|
871344 | if (path.empty()) { |
| 4595 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return std::string(""); |
| 4596 | } | ||
| 4597 | |||
| 4598 | /* We do not need a separator at the end in order to determine what | ||
| 4599 | kind of object it is. So take it off. If it is there and the last | ||
| 4600 | part is actually a file, the correct real path will be returned. */ | ||
| 4601 |
6/6✓ Branch 0 taken 851293 times.
✓ Branch 1 taken 20050 times.
✓ Branch 2 taken 215263 times.
✓ Branch 3 taken 636030 times.
✓ Branch 4 taken 215263 times.
✓ Branch 5 taken 656080 times.
|
871343 | if (in_path.length() > 1 && is_separator(in_path.back())) { |
| 4602 |
1/2✓ Branch 0 taken 215263 times.
✗ Branch 1 not taken.
|
215263 | trim_separator(in_path); |
| 4603 | } | ||
| 4604 | |||
| 4605 | /* Before we make an absolute path, check if this path exists, | ||
| 4606 | and if so, what type it is. */ | ||
| 4607 |
1/2✓ Branch 0 taken 871343 times.
✗ Branch 1 not taken.
|
871343 | os_file_status(in_path.c_str(), &path_exists, &path_type); |
| 4608 | |||
| 4609 |
1/2✓ Branch 0 taken 871343 times.
✗ Branch 1 not taken.
|
871343 | int ret = my_realpath(abspath, in_path.c_str(), MYF(0)); |
| 4610 | |||
| 4611 |
2/2✓ Branch 0 taken 868449 times.
✓ Branch 1 taken 2894 times.
|
871343 | if (ret == 0) { |
| 4612 |
1/2✓ Branch 0 taken 868449 times.
✗ Branch 1 not taken.
|
868449 | real_path.assign(abspath); |
| 4613 | } else { | ||
| 4614 | /* This often happens on non-Windows platforms when the path does not | ||
| 4615 | fully exist yet. */ | ||
| 4616 | |||
| 4617 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2894 times.
|
2894 | if (path_exists) { |
| 4618 | /* my_realpath() failed for some reason other than the path does not | ||
| 4619 | exist. */ | ||
| 4620 | ✗ | if (force) { | |
| 4621 | /* Use the given path and make it comparable. */ | ||
| 4622 | ✗ | real_path.assign(in_path); | |
| 4623 | } else { | ||
| 4624 | /* Return null and make a note of it. Another attempt will be made | ||
| 4625 | later when Fil_path::get_real_path() is called with force=true. */ | ||
| 4626 | ✗ | ib::info(ER_IB_MSG_289) << "my_realpath('" << path | |
| 4627 | ✗ | << "') failed for path type " << path_type; | |
| 4628 | ✗ | return (std::string("")); | |
| 4629 | } | ||
| 4630 | } else { | ||
| 4631 | /* The path does not exist. Try my_realpath() again with the | ||
| 4632 | existing portion of the path. */ | ||
| 4633 | 2894 | std::string ghost; | |
| 4634 |
1/2✓ Branch 0 taken 2894 times.
✗ Branch 1 not taken.
|
2894 | std::string dir = get_existing_path(in_path, ghost); |
| 4635 | |||
| 4636 |
1/2✓ Branch 0 taken 2894 times.
✗ Branch 1 not taken.
|
2894 | ret = my_realpath(abspath, dir.c_str(), MYF(0)); |
| 4637 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2894 times.
|
2894 | ut_ad(ret == 0); |
| 4638 | |||
| 4639 | /* Concatenate the absolute path with the non-existing sub-path. | ||
| 4640 | NOTE: If this path existed, my_realpath() would put a separator | ||
| 4641 | at the end if it is a directory. But since the ghost portion | ||
| 4642 | does not yet exist, we don't know if it is a dir or a file, so | ||
| 4643 | we cannot attach a trailing separator for a directory. So we | ||
| 4644 | trim them off in Fil_path::is_same_as() and is_ancestor(). */ | ||
| 4645 |
1/2✓ Branch 0 taken 2894 times.
✗ Branch 1 not taken.
|
2894 | real_path.assign(abspath); |
| 4646 |
1/2✓ Branch 0 taken 2894 times.
✗ Branch 1 not taken.
|
2894 | append_separator(real_path); |
| 4647 |
1/2✓ Branch 0 taken 2894 times.
✗ Branch 1 not taken.
|
2894 | real_path.append(ghost); |
| 4648 | 2894 | } | |
| 4649 | } | ||
| 4650 | |||
| 4651 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 871343 times.
|
871343 | if (lower_case_file_system) { |
| 4652 | ✗ | Fil_path::to_lower(real_path); | |
| 4653 | } | ||
| 4654 | |||
| 4655 | /* Try to consistently end a directory name with a separator. | ||
| 4656 | On Windows, my_realpath() usually puts a separator at the end | ||
| 4657 | of a directory path (it does not do that for the path "."). | ||
| 4658 | On non-Windows it never does. | ||
| 4659 | So if the separator is missing, decide whether to append it. */ | ||
| 4660 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 871343 times.
|
871343 | ut_ad(!real_path.empty()); |
| 4661 |
2/2✓ Branch 0 taken 871339 times.
✓ Branch 1 taken 4 times.
|
871343 | if (!is_separator(real_path.back())) { |
| 4662 | 871339 | bool add_sep = true; | |
| 4663 |
3/4✓ Branch 0 taken 234910 times.
✓ Branch 1 taken 633537 times.
✓ Branch 2 taken 2892 times.
✗ Branch 3 not taken.
|
871339 | switch (path_type) { |
| 4664 | 234910 | case OS_FILE_TYPE_DIR: | |
| 4665 | case OS_FILE_TYPE_BLOCK: | ||
| 4666 | 234910 | break; | |
| 4667 | 633537 | case OS_FILE_TYPE_FILE: | |
| 4668 | case OS_FILE_TYPE_LINK: | ||
| 4669 | 633537 | add_sep = false; | |
| 4670 | 633537 | break; | |
| 4671 | 2892 | case OS_FILE_TYPE_FAILED: | |
| 4672 | case OS_FILE_TYPE_MISSING: | ||
| 4673 | case OS_FILE_TYPE_NAME_TOO_LONG: | ||
| 4674 | case OS_FILE_PERMISSION_ERROR: | ||
| 4675 | case OS_FILE_TYPE_UNKNOWN: | ||
| 4676 | /* This filepath is missing or cannot be identified for some other | ||
| 4677 | reason. If it ends in a three letter extension, assume it is a file | ||
| 4678 | name and do not add the trailing separator. Otherwise, assume it is | ||
| 4679 | intended to be a directory.*/ | ||
| 4680 | 2892 | size_t s = real_path.size(); | |
| 4681 |
5/8✓ Branch 0 taken 2892 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2005 times.
✓ Branch 3 taken 887 times.
✓ Branch 4 taken 2005 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2005 times.
✗ Branch 7 not taken.
|
2892 | if (s > 4 && real_path[s - 4] == '.' && real_path[s - 3] != '.' && |
| 4682 |
5/8✓ Branch 0 taken 2005 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1969 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 1969 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1969 times.
✗ Branch 7 not taken.
|
2005 | real_path[s - 2] != '.' && real_path[s - 1] != '.' && |
| 4683 |
5/8✓ Branch 0 taken 2892 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1969 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1969 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1929 times.
✓ Branch 7 taken 963 times.
|
7753 | !is_separator(real_path[s - 3]) && |
| 4684 |
3/4✓ Branch 0 taken 1969 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1929 times.
✓ Branch 3 taken 40 times.
|
1969 | !is_separator(real_path[s - 2])) { |
| 4685 | 1929 | add_sep = false; | |
| 4686 | } | ||
| 4687 | } | ||
| 4688 | |||
| 4689 |
2/2✓ Branch 0 taken 235873 times.
✓ Branch 1 taken 635466 times.
|
871339 | if (add_sep) { |
| 4690 |
1/2✓ Branch 0 taken 235873 times.
✗ Branch 1 not taken.
|
235873 | append_separator(real_path); |
| 4691 | } | ||
| 4692 | } | ||
| 4693 | |||
| 4694 | 871343 | return real_path; | |
| 4695 | 871344 | } | |
| 4696 | |||
| 4697 | 1885213 | std::string Fil_path::get_basename(const std::string &filepath) { | |
| 4698 | 1885213 | auto sep = filepath.find_last_of(SEPARATOR); | |
| 4699 | |||
| 4700 | return (sep == std::string::npos) | ||
| 4701 | ? filepath | ||
| 4702 |
2/2✓ Branch 0 taken 353431 times.
✓ Branch 1 taken 1531782 times.
|
1885213 | : filepath.substr(sep + 1, filepath.length() - sep); |
| 4703 | } | ||
| 4704 | |||
| 4705 | /** Constructor | ||
| 4706 | @param[in] dir Directory that the files are under */ | ||
| 4707 | 9887 | Tablespace_files::Tablespace_files(const std::string &dir) | |
| 4708 |
1/2✓ Branch 0 taken 9887 times.
✗ Branch 1 not taken.
|
9887 | : m_ibd_paths(), m_undo_paths(), m_dir(dir) { |
| 4709 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9887 times.
|
9887 | ut_ad(Fil_path::is_separator(dir.back())); |
| 4710 | 9887 | } | |
| 4711 | |||
| 4712 | /** Closes a single-table tablespace. The tablespace must be cached in the | ||
| 4713 | memory cache. Free all pages used by the tablespace. | ||
| 4714 | @param[in] space_id Tablespace ID | ||
| 4715 | @return DB_SUCCESS or error */ | ||
| 4716 | 308 | dberr_t fil_close_tablespace(space_id_t space_id) { | |
| 4717 |
2/4✓ Branch 0 taken 308 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 308 times.
|
308 | ut_ad(!fsp_is_undo_tablespace(space_id)); |
| 4718 |
2/4✓ Branch 0 taken 308 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 308 times.
|
308 | ut_ad(!fsp_is_system_or_temp_tablespace(space_id)); |
| 4719 | |||
| 4720 |
1/2✓ Branch 0 taken 308 times.
✗ Branch 1 not taken.
|
308 | auto shard = fil_system->shard_by_id(space_id); |
| 4721 | |||
| 4722 | 308 | char *path{}; | |
| 4723 | 308 | fil_space_t *space{}; | |
| 4724 | |||
| 4725 |
1/2✓ Branch 0 taken 308 times.
✗ Branch 1 not taken.
|
308 | auto err = shard->wait_for_pending_operations(space_id, space, &path); |
| 4726 | |||
| 4727 |
2/2✓ Branch 0 taken 127 times.
✓ Branch 1 taken 181 times.
|
308 | if (err != DB_SUCCESS) { |
| 4728 | 127 | return err; | |
| 4729 | } | ||
| 4730 | |||
| 4731 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 181 times.
|
181 | ut_a(path != nullptr); |
| 4732 | |||
| 4733 | #ifndef UNIV_HOTBACKUP | ||
| 4734 | 181 | shard->space_prepare_for_delete(space); | |
| 4735 | #else | ||
| 4736 | rw_lock_x_lock(&space->latch, UT_LOCATION_HERE); | ||
| 4737 | |||
| 4738 | /* If the free is successful, the X lock will be released before | ||
| 4739 | the space memory data structure is freed. */ | ||
| 4740 | |||
| 4741 | if (!fil_space_free(space_id, true)) { | ||
| 4742 | rw_lock_x_unlock(&space->latch); | ||
| 4743 | err = DB_TABLESPACE_NOT_FOUND; | ||
| 4744 | } else { | ||
| 4745 | err = DB_SUCCESS; | ||
| 4746 | } | ||
| 4747 | #endif /* !UNIV_HOTBACKUP */ | ||
| 4748 | |||
| 4749 | /* Delete any generated files, otherwise if we drop the database the | ||
| 4750 | remove directory will fail. */ | ||
| 4751 | |||
| 4752 |
2/4✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 181 times.
✗ Branch 3 not taken.
|
181 | auto cfg_name = Fil_path::make_cfg(path); |
| 4753 | |||
| 4754 |
1/2✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
|
181 | if (cfg_name != nullptr) { |
| 4755 |
1/2✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
|
181 | os_file_delete_if_exists(innodb_data_file_key, cfg_name, nullptr); |
| 4756 | |||
| 4757 | 181 | ut::free(cfg_name); | |
| 4758 | } | ||
| 4759 | |||
| 4760 |
2/4✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 181 times.
✗ Branch 3 not taken.
|
181 | auto cfp_name = Fil_path::make_cfp(path); |
| 4761 | |||
| 4762 |
1/2✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
|
181 | if (cfp_name != nullptr) { |
| 4763 |
1/2✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
|
181 | os_file_delete_if_exists(innodb_data_file_key, cfp_name, nullptr); |
| 4764 | |||
| 4765 | 181 | ut::free(cfp_name); | |
| 4766 | } | ||
| 4767 | |||
| 4768 | 181 | ut::free(path); | |
| 4769 | |||
| 4770 | 181 | return err; | |
| 4771 | } | ||
| 4772 | |||
| 4773 | #ifndef UNIV_HOTBACKUP | ||
| 4774 | /** Write a log record about an operation on a tablespace file. | ||
| 4775 | @param[in] type MLOG_FILE_OPEN or MLOG_FILE_DELETE | ||
| 4776 | or MLOG_FILE_CREATE or MLOG_FILE_RENAME | ||
| 4777 | @param[in] space_id Tablespace identifier | ||
| 4778 | @param[in] path File path | ||
| 4779 | @param[in] new_path If type is MLOG_FILE_RENAME, the new name | ||
| 4780 | @param[in] flags If type is MLOG_FILE_CREATE, the space flags | ||
| 4781 | @param[in,out] mtr Mini-transaction */ | ||
| 4782 | 464691 | static void fil_op_write_log(mlog_id_t type, space_id_t space_id, | |
| 4783 | const char *path, const char *new_path, | ||
| 4784 | uint32_t flags, mtr_t *mtr) { | ||
| 4785 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 464691 times.
|
464691 | ut_ad(space_id != TRX_SYS_SPACE); |
| 4786 | |||
| 4787 | 464691 | byte *log_ptr = nullptr; | |
| 4788 | |||
| 4789 |
3/4✓ Branch 0 taken 464691 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 538 times.
✓ Branch 3 taken 464153 times.
|
464691 | if (!mlog_open(mtr, 11 + 4 + 2 + 1, log_ptr)) { |
| 4790 | /* Logging in mtr is switched off during crash recovery: | ||
| 4791 | in that case mlog_open returns nullptr */ | ||
| 4792 | 538 | return; | |
| 4793 | } | ||
| 4794 | |||
| 4795 |
1/2✓ Branch 0 taken 464153 times.
✗ Branch 1 not taken.
|
464153 | log_ptr = mlog_write_initial_log_record_low(type, space_id, 0, log_ptr, mtr); |
| 4796 | |||
| 4797 |
2/2✓ Branch 0 taken 197471 times.
✓ Branch 1 taken 266682 times.
|
464153 | if (type == MLOG_FILE_CREATE) { |
| 4798 |
1/2✓ Branch 0 taken 197471 times.
✗ Branch 1 not taken.
|
197471 | mach_write_to_4(log_ptr, flags); |
| 4799 | 197471 | log_ptr += 4; | |
| 4800 | } | ||
| 4801 | |||
| 4802 | /* Let us store the strings as null-terminated for easier readability | ||
| 4803 | and handling */ | ||
| 4804 | |||
| 4805 | 464153 | ulint len = strlen(path) + 1; | |
| 4806 | |||
| 4807 |
1/2✓ Branch 0 taken 464153 times.
✗ Branch 1 not taken.
|
464153 | mach_write_to_2(log_ptr, len); |
| 4808 | 464153 | log_ptr += 2; | |
| 4809 | |||
| 4810 |
1/2✓ Branch 0 taken 464153 times.
✗ Branch 1 not taken.
|
464153 | mlog_close(mtr, log_ptr); |
| 4811 | |||
| 4812 |
1/2✓ Branch 0 taken 464153 times.
✗ Branch 1 not taken.
|
464153 | mlog_catenate_string(mtr, reinterpret_cast<const byte *>(path), len); |
| 4813 | |||
| 4814 |
2/3✓ Branch 0 taken 79539 times.
✓ Branch 1 taken 384614 times.
✗ Branch 2 not taken.
|
464153 | switch (type) { |
| 4815 | 79539 | case MLOG_FILE_RENAME: | |
| 4816 | |||
| 4817 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79539 times.
|
79539 | ut_ad(strchr(new_path, Fil_path::OS_SEPARATOR) != nullptr); |
| 4818 | |||
| 4819 | 79539 | len = strlen(new_path) + 1; | |
| 4820 | |||
| 4821 |
2/4✓ Branch 0 taken 79539 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79539 times.
|
79539 | ut_a(mlog_open(mtr, 2 + len, log_ptr)); |
| 4822 | |||
| 4823 |
1/2✓ Branch 0 taken 79539 times.
✗ Branch 1 not taken.
|
79539 | mach_write_to_2(log_ptr, len); |
| 4824 | |||
| 4825 | 79539 | log_ptr += 2; | |
| 4826 | |||
| 4827 |
1/2✓ Branch 0 taken 79539 times.
✗ Branch 1 not taken.
|
79539 | mlog_close(mtr, log_ptr); |
| 4828 | |||
| 4829 |
1/2✓ Branch 0 taken 79539 times.
✗ Branch 1 not taken.
|
79539 | mlog_catenate_string(mtr, reinterpret_cast<const byte *>(new_path), len); |
| 4830 | 79539 | break; | |
| 4831 | 384614 | case MLOG_FILE_DELETE: | |
| 4832 | case MLOG_FILE_CREATE: | ||
| 4833 | 384614 | break; | |
| 4834 | ✗ | default: | |
| 4835 | ✗ | ut_d(ut_error); | |
| 4836 | } | ||
| 4837 | } | ||
| 4838 | |||
| 4839 | 4 | bool fil_system_get_file_by_space_id(space_id_t space_id, std::string &name) { | |
| 4840 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
|
4 | ut_a(dict_sys_t::is_reserved(space_id) || srv_is_upgrade_mode); |
| 4841 | |||
| 4842 | 4 | return fil_system->get_file_by_space_id(space_id, name); | |
| 4843 | } | ||
| 4844 | |||
| 4845 | 1196733 | bool fil_system_get_file_by_space_num(space_id_t space_num, | |
| 4846 | space_id_t &space_id, std::string &name) { | ||
| 4847 | 1196733 | return fil_system->get_file_by_space_num(space_num, space_id, name); | |
| 4848 | } | ||
| 4849 | |||
| 4850 | #endif /* !UNIV_HOTBACKUP */ | ||
| 4851 | |||
| 4852 | 187361 | dberr_t Fil_shard::space_delete(space_id_t space_id, buf_remove_t buf_remove) { | |
| 4853 | 187361 | char *path = nullptr; | |
| 4854 | 187361 | fil_space_t *space = nullptr; | |
| 4855 | |||
| 4856 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 187361 times.
|
187361 | ut_ad(!fsp_is_system_tablespace(space_id)); |
| 4857 |
2/4✓ Branch 0 taken 187361 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 187361 times.
|
187361 | ut_ad(!fsp_is_global_temporary(space_id)); |
| 4858 | |||
| 4859 |
1/2✓ Branch 0 taken 187361 times.
✗ Branch 1 not taken.
|
187361 | dberr_t err = wait_for_pending_operations(space_id, space, &path); |
| 4860 | |||
| 4861 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 187325 times.
|
187361 | if (err != DB_SUCCESS) { |
| 4862 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
|
36 | ut_a(err == DB_TABLESPACE_NOT_FOUND); |
| 4863 | 36 | return err; | |
| 4864 | } | ||
| 4865 | |||
| 4866 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 187325 times.
|
187325 | ut_a(path != nullptr); |
| 4867 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 187325 times.
|
187325 | ut_a(space != nullptr); |
| 4868 | |||
| 4869 | #ifndef UNIV_HOTBACKUP | ||
| 4870 | /* IMPORTANT: Because we have set space::stop_new_ops there | ||
| 4871 | can't be any new ibuf merges, reads or flushes. We are here | ||
| 4872 | because file::n_pending was zero above. However, it is still | ||
| 4873 | possible to have pending read and write requests: | ||
| 4874 | |||
| 4875 | A read request can happen because the reader thread has | ||
| 4876 | gone through the ::stop_new_ops check in buf_page_init_for_read() | ||
| 4877 | before the flag was set and has not yet incremented ::n_pending | ||
| 4878 | when we checked it above. | ||
| 4879 | |||
| 4880 | A write request can be issued any time because we don't check | ||
| 4881 | the ::stop_new_ops flag when queueing a block for write. | ||
| 4882 | |||
| 4883 | We deal with pending write requests in the following function | ||
| 4884 | where we'd minimally evict all dirty pages belonging to this | ||
| 4885 | space from the flush_list. Note that if a block is IO-fixed | ||
| 4886 | we'll wait for IO to complete. | ||
| 4887 | |||
| 4888 | For buf_remove == BUF_REMOVE_NONE we mark the fil_space_t instance | ||
| 4889 | as deleted by bumping up the file_space_t::m_version. All pages | ||
| 4890 | that are less than this version number will be discarded. We wait | ||
| 4891 | for any pending IO to complete after that. | ||
| 4892 | |||
| 4893 | To deal with potential read requests, we will check the | ||
| 4894 | ::stop_new_ops flag in fil_io(). */ | ||
| 4895 | |||
| 4896 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 187323 times.
|
187325 | if (buf_remove != BUF_REMOVE_NONE) { |
| 4897 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | buf_LRU_flush_or_remove_pages(space_id, buf_remove, nullptr); |
| 4898 | } | ||
| 4899 | |||
| 4900 | /* Ensure that we write redo log for the operation also within the Clone | ||
| 4901 | notifier block. This is needed because we don't have any mechanism today | ||
| 4902 | to avoid checkpoint crossing the redo log before the actual operation | ||
| 4903 | is complete. Make sure we are not holding shard mutex. */ | ||
| 4904 |
2/4✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 187325 times.
|
187325 | ut_ad(!mutex_owned()); |
| 4905 |
1/2✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
|
187325 | Clone_notify notifier(Clone_notify::Type::SPACE_DROP, space_id, false); |
| 4906 | |||
| 4907 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 187325 times.
|
187325 | if (notifier.failed()) { |
| 4908 | /* Currently post DDL operations are never rolled back. */ | ||
| 4909 | /* purecov: begin deadcode */ | ||
| 4910 | ✗ | ut::free(path); | |
| 4911 | ✗ | ut_d(ut_error); | |
| 4912 | ut_o(return DB_ERROR); | ||
| 4913 | /* purecov: end */ | ||
| 4914 | } | ||
| 4915 | #endif /* !UNIV_HOTBACKUP */ | ||
| 4916 | |||
| 4917 | /* If it is a delete then also delete any generated files, otherwise | ||
| 4918 | when we drop the database the remove directory will fail. */ | ||
| 4919 |
1/2✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
|
187325 | if (space->purpose != FIL_TYPE_TEMPORARY) { |
| 4920 | #ifdef UNIV_HOTBACKUP | ||
| 4921 | /* When replaying the operation in MySQL Enterprise | ||
| 4922 | Backup, we do not try to write any log record. */ | ||
| 4923 | #else /* UNIV_HOTBACKUP */ | ||
| 4924 | /* Before deleting the file, write a log record about it, so that | ||
| 4925 | InnoDB crash recovery will expect the file to be gone. */ | ||
| 4926 |
1/2✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
|
187325 | mtr_t mtr; |
| 4927 | |||
| 4928 |
1/2✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
|
187325 | mtr.start(); |
| 4929 | |||
| 4930 |
1/2✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
|
187325 | fil_op_write_log(MLOG_FILE_DELETE, space_id, path, nullptr, 0, &mtr); |
| 4931 | |||
| 4932 |
1/2✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
|
187325 | mtr.commit(); |
| 4933 | |||
| 4934 |
5/8✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 187324 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
187325 | DBUG_EXECUTE_IF("delete_crash", log_buffer_flush_to_disk(); |
| 4935 | DBUG_SUICIDE();); | ||
| 4936 | |||
| 4937 | /* Even if we got killed shortly after deleting the | ||
| 4938 | tablespace file, the record must have already been | ||
| 4939 | written to the redo log. */ | ||
| 4940 |
2/4✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187324 times.
✗ Branch 3 not taken.
|
187324 | log_write_up_to(*log_sys, mtr.commit_lsn(), true); |
| 4941 | #endif /* UNIV_HOTBACKUP */ | ||
| 4942 | |||
| 4943 |
2/4✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187324 times.
✗ Branch 3 not taken.
|
187324 | char *cfg_name = Fil_path::make_cfg(path); |
| 4944 | |||
| 4945 |
1/2✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
|
187324 | if (cfg_name != nullptr) { |
| 4946 |
1/2✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
|
187324 | os_file_delete_if_exists(innodb_data_file_key, cfg_name, nullptr); |
| 4947 | |||
| 4948 | 187324 | ut::free(cfg_name); | |
| 4949 | } | ||
| 4950 | |||
| 4951 |
2/4✓ Branch 0 taken 187323 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187324 times.
✗ Branch 3 not taken.
|
187324 | char *cfp_name = Fil_path::make_cfp(path); |
| 4952 | |||
| 4953 |
1/2✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
|
187324 | if (cfp_name != nullptr) { |
| 4954 |
1/2✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
|
187324 | os_file_delete_if_exists(innodb_data_file_key, cfp_name, nullptr); |
| 4955 | |||
| 4956 | 187324 | ut::free(cfp_name); | |
| 4957 | } | ||
| 4958 | 187324 | } | |
| 4959 | |||
| 4960 |
1/2✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
|
187324 | mutex_acquire(); |
| 4961 | |||
| 4962 | /* Double check the sanity of pending ops after reacquiring | ||
| 4963 | the fil_system::mutex. */ | ||
| 4964 |
2/4✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187324 times.
✗ Branch 3 not taken.
|
187324 | if (const fil_space_t *s = get_space_by_id(space_id)) { |
| 4965 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 187324 times.
|
187324 | ut_a(s == space); |
| 4966 | |||
| 4967 |
1/2✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
|
187324 | space->set_deleted(); |
| 4968 | |||
| 4969 | #ifndef UNIV_HOTBACKUP | ||
| 4970 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 187324 times.
|
187324 | ut_a(space->files.size() == 1); |
| 4971 | 187324 | auto &file = space->files.front(); | |
| 4972 | |||
| 4973 | /* Wait for any pending writes. */ | ||
| 4974 |
3/4✓ Branch 0 taken 167823 times.
✓ Branch 1 taken 187324 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 187324 times.
|
355147 | while (file.n_pending_ios > 0 || file.n_pending_flushes > 0 || |
| 4975 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 187324 times.
|
187324 | file.is_being_extended) { |
| 4976 | /* Release and reacquire the mutex because we want the IO to complete. */ | ||
| 4977 |
1/2✓ Branch 0 taken 167823 times.
✗ Branch 1 not taken.
|
167823 | mutex_release(); |
| 4978 | |||
| 4979 | 167823 | std::this_thread::yield(); | |
| 4980 | |||
| 4981 |
1/2✓ Branch 0 taken 167823 times.
✗ Branch 1 not taken.
|
167823 | mutex_acquire(); |
| 4982 | } | ||
| 4983 | |||
| 4984 |
1/2✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
|
187324 | m_deleted_spaces.push_back({space->id, space}); |
| 4985 | #endif /* !UNIV_HOTBACKUP */ | ||
| 4986 | |||
| 4987 |
1/2✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
|
187324 | space_detach(space); |
| 4988 | |||
| 4989 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 187324 times.
|
187324 | ut_a(space->files.size() == 1); |
| 4990 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 187324 times.
|
187324 | ut_a(space->files.front().n_pending_ios == 0); |
| 4991 |
1/2✓ Branch 0 taken 187323 times.
✗ Branch 1 not taken.
|
187324 | space_remove_from_lookup_maps(space_id); |
| 4992 | |||
| 4993 |
1/2✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
|
187323 | mutex_release(); |
| 4994 | |||
| 4995 | #ifdef UNIV_HOTBACKUP | ||
| 4996 | /* For usage inside MEB we don't support lazy stale page eviction, we just | ||
| 4997 | do what fil_shard::purge() does directly here. */ | ||
| 4998 | space_free_low(space); | ||
| 4999 | #endif /* UNIV_HOTBACKUP */ | ||
| 5000 | |||
| 5001 |
3/6✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 187324 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 187324 times.
|
187324 | if (!os_file_delete(innodb_data_file_key, path) && |
| 5002 | ✗ | !os_file_delete_if_exists(innodb_data_file_key, path, nullptr)) { | |
| 5003 | /* Note: This is because we have removed the | ||
| 5004 | tablespace instance from the cache. */ | ||
| 5005 | |||
| 5006 | ✗ | err = DB_IO_ERROR; | |
| 5007 | } | ||
| 5008 | } else { | ||
| 5009 | ✗ | mutex_release(); | |
| 5010 | |||
| 5011 | ✗ | err = DB_TABLESPACE_NOT_FOUND; | |
| 5012 | } | ||
| 5013 | |||
| 5014 | 187324 | ut::free(path); | |
| 5015 | 187324 | return err; | |
| 5016 | 187324 | } | |
| 5017 | |||
| 5018 | 187361 | dberr_t fil_delete_tablespace(space_id_t space_id, buf_remove_t buf_remove) { | |
| 5019 | 187361 | auto shard = fil_system->shard_by_id(space_id); | |
| 5020 | |||
| 5021 | 187361 | return shard->space_delete(space_id, buf_remove); | |
| 5022 | } | ||
| 5023 | |||
| 5024 | 79375 | dberr_t Fil_shard::space_prepare_for_truncate(space_id_t space_id, | |
| 5025 | fil_space_t *&space) { | ||
| 5026 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79375 times.
|
79375 | ut_ad(space_id != TRX_SYS_SPACE); |
| 5027 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79375 times.
|
79375 | ut_ad(!fsp_is_system_tablespace(space_id)); |
| 5028 |
2/4✓ Branch 0 taken 79375 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79375 times.
|
79375 | ut_ad(!fsp_is_global_temporary(space_id)); |
| 5029 | |||
| 5030 | 79375 | char *path{}; | |
| 5031 |
1/2✓ Branch 0 taken 79375 times.
✗ Branch 1 not taken.
|
79375 | auto err = wait_for_pending_operations(space_id, space, &path); |
| 5032 | |||
| 5033 | 79375 | ut::free(path); | |
| 5034 | |||
| 5035 | 79375 | return err; | |
| 5036 | } | ||
| 5037 | |||
| 5038 | 79375 | bool Fil_shard::space_truncate(space_id_t space_id, page_no_t size_in_pages) { | |
| 5039 | #ifndef UNIV_HOTBACKUP | ||
| 5040 | 79375 | fil_space_t *space{}; | |
| 5041 | |||
| 5042 | /* Step-1: Prepare tablespace for truncate. This involves | ||
| 5043 | stopping all the new operations + IO on that tablespace. Any future attempts | ||
| 5044 | to flush will be ignored and pages discarded. */ | ||
| 5045 |
2/4✓ Branch 0 taken 79375 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79375 times.
|
79375 | if (space_prepare_for_truncate(space_id, space) != DB_SUCCESS) { |
| 5046 | ✗ | return false; | |
| 5047 | } | ||
| 5048 | |||
| 5049 |
1/2✓ Branch 0 taken 79375 times.
✗ Branch 1 not taken.
|
79375 | mutex_acquire(); |
| 5050 | |||
| 5051 | /* Step-2: Mark the tablespace pages in the buffer pool as stale by bumping | ||
| 5052 | the version number of the space. Those stale pages will be ignored and freed | ||
| 5053 | lazily later. This includes AHI, for which entries will be removed on | ||
| 5054 | buf_page_free_stale*() -> buf_LRU_free_page -> | ||
| 5055 | btr_search_drop_page_hash_index() */ | ||
| 5056 |
1/2✓ Branch 0 taken 79375 times.
✗ Branch 1 not taken.
|
79375 | space->bump_version(); |
| 5057 | |||
| 5058 | /* Step-3: Truncate the tablespace and accordingly update | ||
| 5059 | the fil_space_t handler that is used to access this tablespace. */ | ||
| 5060 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79375 times.
|
79375 | ut_a(space->files.size() == 1); |
| 5061 | |||
| 5062 | 79375 | auto &file = space->files.front(); | |
| 5063 | |||
| 5064 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 79353 times.
|
79375 | if (!file.is_open) { |
| 5065 |
2/4✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
|
22 | if (!open_file(&file)) { |
| 5066 | ✗ | mutex_release(); | |
| 5067 | ✗ | return false; | |
| 5068 | } | ||
| 5069 | } | ||
| 5070 | |||
| 5071 | 79375 | space->size = file.size = size_in_pages; | |
| 5072 | |||
| 5073 |
1/2✓ Branch 0 taken 79373 times.
✗ Branch 1 not taken.
|
79375 | bool success = os_file_truncate(file.name, file.handle, 0); |
| 5074 | |||
| 5075 |
1/2✓ Branch 0 taken 79374 times.
✗ Branch 1 not taken.
|
79373 | if (success) { |
| 5076 | 79374 | os_offset_t size = size_in_pages * UNIV_PAGE_SIZE; | |
| 5077 | |||
| 5078 |
1/2✓ Branch 0 taken 79371 times.
✗ Branch 1 not taken.
|
79374 | success = os_file_set_size(file.name, file.handle, 0, size, true); |
| 5079 | |||
| 5080 |
1/2✓ Branch 0 taken 79371 times.
✗ Branch 1 not taken.
|
79371 | if (success) { |
| 5081 | 79371 | space->stop_new_ops = false; | |
| 5082 | } | ||
| 5083 | } | ||
| 5084 | |||
| 5085 |
1/2✓ Branch 0 taken 79373 times.
✗ Branch 1 not taken.
|
79370 | mutex_release(); |
| 5086 | |||
| 5087 | 79373 | return success; | |
| 5088 | #else | ||
| 5089 | /* Truncating a tablespace is not supported for MEB. */ | ||
| 5090 | ut_error; | ||
| 5091 | #endif | ||
| 5092 | } | ||
| 5093 | |||
| 5094 | /** Truncate the tablespace to needed size. | ||
| 5095 | @param[in] space_id Tablespace ID to truncate | ||
| 5096 | @param[in] size_in_pages Truncate size. | ||
| 5097 | @return true if truncate was successful. */ | ||
| 5098 | 79375 | bool fil_truncate_tablespace(space_id_t space_id, page_no_t size_in_pages) { | |
| 5099 | 79375 | auto shard = fil_system->shard_by_id(space_id); | |
| 5100 | |||
| 5101 | 79375 | return shard->space_truncate(space_id, size_in_pages); | |
| 5102 | } | ||
| 5103 | |||
| 5104 | #ifdef UNIV_DEBUG | ||
| 5105 | /** Increase redo skipped count for a tablespace. | ||
| 5106 | @param[in] space_id Tablespace ID */ | ||
| 5107 | 54672 | void fil_space_inc_redo_skipped_count(space_id_t space_id) { | |
| 5108 | 54672 | auto shard = fil_system->shard_by_id(space_id); | |
| 5109 | |||
| 5110 | 54671 | shard->mutex_acquire(); | |
| 5111 | |||
| 5112 | 54671 | fil_space_t *space = shard->get_space_by_id(space_id); | |
| 5113 | |||
| 5114 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 54672 times.
|
54673 | ut_a(space != nullptr); |
| 5115 | |||
| 5116 | 54672 | ++space->redo_skipped_count; | |
| 5117 | |||
| 5118 | 54672 | shard->mutex_release(); | |
| 5119 | 54671 | } | |
| 5120 | |||
| 5121 | /** Decrease redo skipped count for a tablespace. | ||
| 5122 | @param[in] space_id Tablespace ID */ | ||
| 5123 | 54673 | void fil_space_dec_redo_skipped_count(space_id_t space_id) { | |
| 5124 | 54673 | auto shard = fil_system->shard_by_id(space_id); | |
| 5125 | |||
| 5126 | 54673 | shard->mutex_acquire(); | |
| 5127 | |||
| 5128 | 54673 | fil_space_t *space = shard->get_space_by_id(space_id); | |
| 5129 | |||
| 5130 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 54673 times.
|
54673 | ut_a(space != nullptr); |
| 5131 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 54673 times.
|
54673 | ut_a(space->redo_skipped_count > 0); |
| 5132 | |||
| 5133 | 54673 | --space->redo_skipped_count; | |
| 5134 | |||
| 5135 | 54673 | shard->mutex_release(); | |
| 5136 | 54673 | } | |
| 5137 | |||
| 5138 | /** Check whether a single-table tablespace is redo skipped. | ||
| 5139 | @param[in] space_id Tablespace ID | ||
| 5140 | @return true if redo skipped */ | ||
| 5141 | 129510 | bool fil_space_is_redo_skipped(space_id_t space_id) { | |
| 5142 | 129510 | auto shard = fil_system->shard_by_id(space_id); | |
| 5143 | |||
| 5144 | 129510 | shard->mutex_acquire(); | |
| 5145 | |||
| 5146 | 129510 | fil_space_t *space = shard->get_space_by_id(space_id); | |
| 5147 | |||
| 5148 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 129510 times.
|
129510 | ut_a(space != nullptr); |
| 5149 | |||
| 5150 | 129510 | bool is_redo_skipped = space->redo_skipped_count > 0; | |
| 5151 | |||
| 5152 | 129510 | shard->mutex_release(); | |
| 5153 | |||
| 5154 | 129510 | return is_redo_skipped; | |
| 5155 | } | ||
| 5156 | #endif /* UNIV_DEBUG */ | ||
| 5157 | |||
| 5158 | #ifndef UNIV_HOTBACKUP | ||
| 5159 | |||
| 5160 | /** Discards a single-table tablespace. The tablespace must be cached in the | ||
| 5161 | memory cache. Discarding is like deleting a tablespace, but | ||
| 5162 | |||
| 5163 | 1. We do not drop the table from the data dictionary; | ||
| 5164 | |||
| 5165 | 2. We remove all insert buffer entries for the tablespace immediately; | ||
| 5166 | in DROP TABLE they are only removed gradually in the background; | ||
| 5167 | |||
| 5168 | 3. When the user does IMPORT TABLESPACE, the tablespace will have the | ||
| 5169 | same id as it originally had. | ||
| 5170 | |||
| 5171 | 4. Free all the pages in use by the tablespace if rename=true. | ||
| 5172 | @param[in] space_id Tablespace ID | ||
| 5173 | @return DB_SUCCESS or error */ | ||
| 5174 | 765 | dberr_t fil_discard_tablespace(space_id_t space_id) { | |
| 5175 | dberr_t err; | ||
| 5176 | |||
| 5177 | 765 | err = fil_delete_tablespace(space_id, BUF_REMOVE_NONE); | |
| 5178 | |||
| 5179 |
2/4✓ Branch 0 taken 749 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
765 | switch (err) { |
| 5180 | 749 | case DB_SUCCESS: | |
| 5181 | 749 | break; | |
| 5182 | |||
| 5183 | ✗ | case DB_IO_ERROR: | |
| 5184 | |||
| 5185 | ✗ | ib::warn(ER_IB_MSG_291, ulong{space_id}, ut_strerr(err)); | |
| 5186 | ✗ | break; | |
| 5187 | |||
| 5188 | 16 | case DB_TABLESPACE_NOT_FOUND: | |
| 5189 | |||
| 5190 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | ib::warn(ER_IB_MSG_292, ulong{space_id}, ut_strerr(err)); |
| 5191 | 16 | break; | |
| 5192 | |||
| 5193 | ✗ | default: | |
| 5194 | ✗ | ut_error; | |
| 5195 | } | ||
| 5196 | |||
| 5197 | 765 | return err; | |
| 5198 | } | ||
| 5199 | |||
| 5200 | /** Write redo log for renaming a file. | ||
| 5201 | @param[in] space_id Tablespace id | ||
| 5202 | @param[in] old_name Tablespace file name | ||
| 5203 | @param[in] new_name Tablespace file name after renaming | ||
| 5204 | @param[in,out] mtr Mini-transaction */ | ||
| 5205 | 79718 | static void fil_name_write_rename(space_id_t space_id, const char *old_name, | |
| 5206 | const char *new_name, mtr_t *mtr) { | ||
| 5207 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79718 times.
|
79718 | ut_ad(!fsp_is_system_or_temp_tablespace(space_id)); |
| 5208 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79718 times.
|
79718 | ut_ad(!fsp_is_undo_tablespace(space_id)); |
| 5209 | |||
| 5210 | /* Note: A checkpoint can take place here. */ | ||
| 5211 | |||
| 5212 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 79717 times.
|
79718 | DBUG_EXECUTE_IF("ib_crash_rename_log_1", DBUG_SUICIDE();); |
| 5213 | |||
| 5214 | static const auto type = MLOG_FILE_RENAME; | ||
| 5215 | |||
| 5216 | 79717 | fil_op_write_log(type, space_id, old_name, new_name, 0, mtr); | |
| 5217 | |||
| 5218 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79717 times.
|
79717 | DBUG_EXECUTE_IF("ib_crash_rename_log_2", DBUG_SUICIDE();); |
| 5219 | |||
| 5220 | /* Note: A checkpoint can take place here too before we | ||
| 5221 | have physically renamed the file. */ | ||
| 5222 | 79717 | } | |
| 5223 | |||
| 5224 | #ifdef UNIV_LINUX | ||
| 5225 | /* Write a redo log record for adding pages to a tablespace | ||
| 5226 | @param[in] space_id Space ID | ||
| 5227 | @param[in] offset Offset from where the file | ||
| 5228 | is extended | ||
| 5229 | @param[in] size Number of bytes by which the file | ||
| 5230 | is extended starting from the offset | ||
| 5231 | @param[in,out] mtr Mini-transaction */ | ||
| 5232 | 183399 | static void fil_op_write_space_extend(space_id_t space_id, os_offset_t offset, | |
| 5233 | os_offset_t size, mtr_t *mtr) { | ||
| 5234 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 183399 times.
|
183399 | ut_ad(space_id != TRX_SYS_SPACE); |
| 5235 | |||
| 5236 | byte *log_ptr; | ||
| 5237 | |||
| 5238 |
3/4✓ Branch 0 taken 183399 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 366 times.
✓ Branch 3 taken 183033 times.
|
183399 | if (!mlog_open(mtr, 7 + 8 + 8, log_ptr)) { |
| 5239 | /* Logging in mtr is switched off during crash recovery: | ||
| 5240 | in that case mlog_open returns nullptr */ | ||
| 5241 | 366 | return; | |
| 5242 | } | ||
| 5243 | |||
| 5244 | #ifdef UNIV_DEBUG | ||
| 5245 | 183033 | byte *start_log = log_ptr; | |
| 5246 | #endif /* UNIV_DEBUG */ | ||
| 5247 | |||
| 5248 |
1/2✓ Branch 0 taken 183033 times.
✗ Branch 1 not taken.
|
183033 | log_ptr = mlog_write_initial_log_record_low(MLOG_FILE_EXTEND, space_id, 0, |
| 5249 | log_ptr, mtr); | ||
| 5250 | |||
| 5251 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 183033 times.
|
183033 | ut_ad(size > 0); |
| 5252 | |||
| 5253 | /* Write the starting offset in the file */ | ||
| 5254 |
1/2✓ Branch 0 taken 183033 times.
✗ Branch 1 not taken.
|
183033 | mach_write_to_8(log_ptr, offset); |
| 5255 | 183033 | log_ptr += 8; | |
| 5256 | |||
| 5257 | /* Write the size by which file needs to be extended from | ||
| 5258 | the given offset */ | ||
| 5259 |
1/2✓ Branch 0 taken 183033 times.
✗ Branch 1 not taken.
|
183033 | mach_write_to_8(log_ptr, size); |
| 5260 | 183033 | log_ptr += 8; | |
| 5261 | |||
| 5262 | #ifdef UNIV_DEBUG | ||
| 5263 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 183033 times.
|
183033 | ut_ad(log_ptr <= start_log + 23); |
| 5264 | #endif /* UNIV_DEBUG */ | ||
| 5265 | |||
| 5266 |
1/2✓ Branch 0 taken 183033 times.
✗ Branch 1 not taken.
|
183033 | mlog_close(mtr, log_ptr); |
| 5267 | } | ||
| 5268 | #endif | ||
| 5269 | #endif /* !UNIV_HOTBACKUP */ | ||
| 5270 | |||
| 5271 | /** Allocate and build a file name from a path, a table or tablespace name | ||
| 5272 | and a suffix. | ||
| 5273 | @param[in] path_in nullptr or the direcory path or the full path | ||
| 5274 | and filename | ||
| 5275 | @param[in] name_in nullptr if path is full, or Table/Tablespace | ||
| 5276 | name | ||
| 5277 | @param[in] ext the file extension to use | ||
| 5278 | @param[in] trim whether last name on the path should be trimmed | ||
| 5279 | @return own: file name; must be freed by ut::free() */ | ||
| 5280 | 1037829 | char *Fil_path::make(const std::string &path_in, const std::string &name_in, | |
| 5281 | ib_file_suffix ext, bool trim) { | ||
| 5282 | /* The path should be a directory and should not contain the | ||
| 5283 | basename of the file. If the path is empty, we will use the | ||
| 5284 | default path, */ | ||
| 5285 | |||
| 5286 |
4/6✓ Branch 0 taken 621625 times.
✓ Branch 1 taken 416208 times.
✓ Branch 2 taken 621622 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1037830 times.
|
1037829 | ut_ad(!path_in.empty() || !name_in.empty()); |
| 5287 | |||
| 5288 | 1037830 | std::string path; | |
| 5289 | |||
| 5290 |
2/2✓ Branch 0 taken 621622 times.
✓ Branch 1 taken 416208 times.
|
1037833 | if (path_in.empty()) { |
| 5291 |
2/4✓ Branch 0 taken 621622 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 621622 times.
|
621622 | if (is_absolute_path(name_in)) { |
| 5292 | ✗ | path = ""; | |
| 5293 | } else { | ||
| 5294 |
1/2✓ Branch 0 taken 621622 times.
✗ Branch 1 not taken.
|
621622 | path.assign(MySQL_datadir_path); |
| 5295 | } | ||
| 5296 | } else { | ||
| 5297 |
1/2✓ Branch 0 taken 416209 times.
✗ Branch 1 not taken.
|
416208 | path.assign(path_in); |
| 5298 | } | ||
| 5299 | |||
| 5300 | 1037831 | std::string name; | |
| 5301 | |||
| 5302 |
2/2✓ Branch 0 taken 662430 times.
✓ Branch 1 taken 375403 times.
|
1037833 | if (!name_in.empty()) { |
| 5303 |
1/2✓ Branch 0 taken 662429 times.
✗ Branch 1 not taken.
|
662430 | name.assign(name_in); |
| 5304 | } | ||
| 5305 | |||
| 5306 | /* Do not prepend the datadir path (which must be DOT_SLASH) | ||
| 5307 | if the name is an absolute path or a relative path like | ||
| 5308 | DOT_SLASH or DOT_DOT_SLASH. */ | ||
| 5309 |
11/18✓ Branch 0 taken 1037832 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1037825 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 1037829 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1037821 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1037813 times.
✓ Branch 9 taken 8 times.
✓ Branch 10 taken 1037823 times.
✓ Branch 11 taken 10 times.
✓ Branch 12 taken 16 times.
✓ Branch 13 taken 1037817 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
3113481 | if (is_absolute_path(name) || has_prefix(name, DOT_SLASH) || |
| 5310 |
10/16✓ Branch 0 taken 1037819 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1037817 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1037814 times.
✓ Branch 6 taken 1037817 times.
✓ Branch 7 taken 15 times.
✓ Branch 8 taken 1037817 times.
✓ Branch 9 taken 15 times.
✓ Branch 10 taken 1037827 times.
✓ Branch 11 taken 5 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
2075645 | has_prefix(name, DOT_DOT_SLASH)) { |
| 5311 | 16 | path.clear(); | |
| 5312 | } | ||
| 5313 | |||
| 5314 | 1037833 | std::string filepath; | |
| 5315 | |||
| 5316 |
2/2✓ Branch 0 taken 1037816 times.
✓ Branch 1 taken 16 times.
|
1037831 | if (!path.empty()) { |
| 5317 |
1/2✓ Branch 0 taken 1037817 times.
✗ Branch 1 not taken.
|
1037816 | filepath.assign(path); |
| 5318 | } | ||
| 5319 | |||
| 5320 |
2/2✓ Branch 0 taken 4219 times.
✓ Branch 1 taken 1033614 times.
|
1037833 | if (trim) { |
| 5321 | /* Find the offset of the last DIR separator and set it to | ||
| 5322 | null in order to strip off the old basename from this path. */ | ||
| 5323 | 4219 | auto pos = filepath.find_last_of(SEPARATOR); | |
| 5324 | |||
| 5325 |
1/2✓ Branch 0 taken 4219 times.
✗ Branch 1 not taken.
|
4219 | if (pos != std::string::npos) { |
| 5326 |
1/2✓ Branch 0 taken 4219 times.
✗ Branch 1 not taken.
|
4219 | filepath.resize(pos); |
| 5327 | } | ||
| 5328 | } | ||
| 5329 | |||
| 5330 |
2/2✓ Branch 0 taken 662429 times.
✓ Branch 1 taken 375404 times.
|
1037833 | if (!name.empty()) { |
| 5331 |
1/2✓ Branch 0 taken 662429 times.
✗ Branch 1 not taken.
|
662429 | append_separator(filepath); |
| 5332 | |||
| 5333 |
1/2✓ Branch 0 taken 662428 times.
✗ Branch 1 not taken.
|
662429 | filepath.append(name); |
| 5334 | } | ||
| 5335 | |||
| 5336 | /* Make sure that the specified suffix is at the end. */ | ||
| 5337 |
2/2✓ Branch 0 taken 999129 times.
✓ Branch 1 taken 38703 times.
|
1037832 | if (ext != NO_EXT) { |
| 5338 | 999129 | const auto suffix = dot_ext[ext]; | |
| 5339 | 999129 | size_t len = strlen(suffix); | |
| 5340 | |||
| 5341 | /* This assumes that the suffix starts with '.'. If the | ||
| 5342 | first char of the suffix is found in the filepath at the | ||
| 5343 | same length as the suffix from the end, then we will assume | ||
| 5344 | that there is a previous suffix that needs to be replaced. */ | ||
| 5345 | |||
| 5346 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 999129 times.
|
999129 | ut_ad(*suffix == '.'); |
| 5347 | |||
| 5348 |
5/6✓ Branch 0 taken 999129 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 376161 times.
✓ Branch 3 taken 622968 times.
✓ Branch 4 taken 376161 times.
✓ Branch 5 taken 622968 times.
|
999129 | if (filepath.length() > len && *(filepath.end() - len) == *suffix) { |
| 5349 |
1/2✓ Branch 0 taken 376161 times.
✗ Branch 1 not taken.
|
376161 | filepath.replace(filepath.end() - len, filepath.end(), suffix); |
| 5350 | } else { | ||
| 5351 |
1/2✓ Branch 0 taken 622968 times.
✗ Branch 1 not taken.
|
622968 | filepath.append(suffix); |
| 5352 | } | ||
| 5353 | } | ||
| 5354 | |||
| 5355 | 1037832 | normalize(filepath); | |
| 5356 | |||
| 5357 |
1/2✓ Branch 0 taken 1037832 times.
✗ Branch 1 not taken.
|
2075667 | return mem_strdup(filepath.c_str()); |
| 5358 | 1037832 | } | |
| 5359 | |||
| 5360 | 250511 | bool Fil_path::parse_file_path(const std::string &file_path, | |
| 5361 | ib_file_suffix extn, std::string &dict_name) { | ||
| 5362 |
1/2✓ Branch 0 taken 250511 times.
✗ Branch 1 not taken.
|
250511 | dict_name.assign(file_path); |
| 5363 |
3/4✓ Branch 0 taken 250511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 498 times.
✓ Branch 3 taken 250013 times.
|
250511 | if (!Fil_path::truncate_suffix(extn, dict_name)) { |
| 5364 | 498 | dict_name.clear(); | |
| 5365 | 498 | return false; | |
| 5366 | } | ||
| 5367 | |||
| 5368 | /* Extract table name */ | ||
| 5369 | 250013 | auto table_pos = dict_name.find_last_of(SEPARATOR); | |
| 5370 |
2/2✓ Branch 0 taken 849 times.
✓ Branch 1 taken 249164 times.
|
250013 | if (table_pos == std::string::npos) { |
| 5371 | 849 | dict_name.clear(); | |
| 5372 | 849 | return false; | |
| 5373 | } | ||
| 5374 |
1/2✓ Branch 0 taken 249164 times.
✗ Branch 1 not taken.
|
249164 | std::string table_name = dict_name.substr(table_pos + 1); |
| 5375 |
1/2✓ Branch 0 taken 249164 times.
✗ Branch 1 not taken.
|
249164 | dict_name.resize(table_pos); |
| 5376 | |||
| 5377 | /* Extract schema name */ | ||
| 5378 | 249164 | auto schema_pos = dict_name.find_last_of(SEPARATOR); | |
| 5379 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 249129 times.
|
249164 | if (schema_pos == std::string::npos) { |
| 5380 | 35 | dict_name.clear(); | |
| 5381 | 35 | return false; | |
| 5382 | } | ||
| 5383 |
1/2✓ Branch 0 taken 249129 times.
✗ Branch 1 not taken.
|
249129 | std::string schema_name = dict_name.substr(schema_pos + 1); |
| 5384 | |||
| 5385 | /* Build dictionary table name schema/table form. */ | ||
| 5386 |
1/2✓ Branch 0 taken 249129 times.
✗ Branch 1 not taken.
|
249129 | dict_name.assign(schema_name); |
| 5387 |
1/2✓ Branch 0 taken 249129 times.
✗ Branch 1 not taken.
|
249129 | dict_name.push_back(DB_SEPARATOR); |
| 5388 |
1/2✓ Branch 0 taken 249129 times.
✗ Branch 1 not taken.
|
249129 | dict_name.append(table_name); |
| 5389 | 249129 | return true; | |
| 5390 | 249164 | } | |
| 5391 | |||
| 5392 | 56249 | std::string Fil_path::make_new_path(const std::string &path_in, | |
| 5393 | const std::string &name_in, | ||
| 5394 | ib_file_suffix extn) { | ||
| 5395 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56249 times.
|
56249 | ut_a(Fil_path::has_suffix(extn, path_in)); |
| 5396 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56249 times.
|
56249 | ut_a(!Fil_path::has_suffix(extn, name_in)); |
| 5397 | |||
| 5398 | 56249 | std::string path(path_in); | |
| 5399 | |||
| 5400 | 56249 | auto pos = path.find_last_of(SEPARATOR); | |
| 5401 | |||
| 5402 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56249 times.
|
56249 | ut_a(pos != std::string::npos); |
| 5403 | |||
| 5404 |
1/2✓ Branch 0 taken 56249 times.
✗ Branch 1 not taken.
|
56249 | path.resize(pos); |
| 5405 | |||
| 5406 | 56249 | pos = path.find_last_of(SEPARATOR); | |
| 5407 | |||
| 5408 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56249 times.
|
56249 | ut_a(pos != std::string::npos); |
| 5409 | |||
| 5410 |
1/2✓ Branch 0 taken 56249 times.
✗ Branch 1 not taken.
|
56249 | path.resize(pos + 1); |
| 5411 | |||
| 5412 |
2/4✓ Branch 0 taken 56249 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56249 times.
✗ Branch 3 not taken.
|
56249 | path.append(name_in + dot_ext[extn]); |
| 5413 | |||
| 5414 | 56249 | normalize(path); | |
| 5415 | |||
| 5416 | 56249 | return path; | |
| 5417 | } | ||
| 5418 | |||
| 5419 | /** This function reduces a null-terminated full remote path name | ||
| 5420 | into the path that is sent by MySQL for DATA DIRECTORY clause. | ||
| 5421 | It replaces the 'databasename/tablename.ibd' found at the end of the | ||
| 5422 | path with just 'tablename'. | ||
| 5423 | |||
| 5424 | Since the result is always smaller than the path sent in, no new | ||
| 5425 | memory is allocated. The caller should allocate memory for the path | ||
| 5426 | sent in. This function manipulates that path in place. If the path | ||
| 5427 | format is not as expected, set data_dir_path to "" and return. | ||
| 5428 | |||
| 5429 | The result is used to inform a SHOW CREATE TABLE command. | ||
| 5430 | @param[in,out] data_dir_path Full path/data_dir_path */ | ||
| 5431 | 208 | void Fil_path::make_data_dir_path(char *data_dir_path) { | |
| 5432 | /* Replace the period before the extension with a null byte. */ | ||
| 5433 |
3/6✓ Branch 0 taken 208 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 208 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 208 times.
|
208 | ut_ad(has_suffix(IBD, data_dir_path)); |
| 5434 | 208 | char *dot = strrchr((char *)data_dir_path, '.'); | |
| 5435 | 208 | *dot = '\0'; | |
| 5436 | |||
| 5437 | /* The tablename starts after the last slash. */ | ||
| 5438 | 208 | char *base_slash = strrchr((char *)data_dir_path, OS_PATH_SEPARATOR); | |
| 5439 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
|
208 | ut_ad(base_slash != nullptr); |
| 5440 | |||
| 5441 | 208 | *base_slash = '\0'; | |
| 5442 | |||
| 5443 |
1/2✓ Branch 0 taken 208 times.
✗ Branch 1 not taken.
|
208 | std::string base_name{base_slash + 1}; |
| 5444 | |||
| 5445 | /* The database name starts after the next to last slash. */ | ||
| 5446 | 208 | char *db_slash = strrchr((char *)data_dir_path, OS_SEPARATOR); | |
| 5447 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
|
208 | ut_ad(db_slash != nullptr); |
| 5448 | 208 | char *db_name = db_slash + 1; | |
| 5449 | |||
| 5450 | /* Overwrite the db_name with the base_name. */ | ||
| 5451 | 208 | memmove(db_name, base_name.c_str(), base_name.length()); | |
| 5452 | 208 | db_name[base_name.length()] = '\0'; | |
| 5453 | 208 | } | |
| 5454 | |||
| 5455 | /** Test if a tablespace file can be renamed to a new filepath by checking | ||
| 5456 | if that the old filepath exists and the new filepath does not exist. | ||
| 5457 | @param[in] space_id Tablespace ID | ||
| 5458 | @param[in] old_path Old filepath | ||
| 5459 | @param[in] new_path New filepath | ||
| 5460 | @param[in] is_discarded Whether the tablespace is discarded | ||
| 5461 | @return innodb error code */ | ||
| 5462 | 101909 | dberr_t fil_rename_tablespace_check(space_id_t space_id, const char *old_path, | |
| 5463 | const char *new_path, bool is_discarded) { | ||
| 5464 | bool exists; | ||
| 5465 | os_file_type_t ftype; | ||
| 5466 | |||
| 5467 |
6/10✓ Branch 0 taken 101905 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 101905 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 101905 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 101905 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 101909 times.
|
101909 | if (!is_discarded && os_file_status(old_path, &exists, &ftype) && !exists) { |
| 5468 | ✗ | ib::error(ER_IB_MSG_293, old_path, new_path, ulong{space_id}); | |
| 5469 | ✗ | return DB_TABLESPACE_NOT_FOUND; | |
| 5470 | } | ||
| 5471 | |||
| 5472 |
6/8✓ Branch 0 taken 101909 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 101909 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 101898 times.
✓ Branch 6 taken 11 times.
✓ Branch 7 taken 101898 times.
|
101909 | if (!os_file_status(new_path, &exists, &ftype) || exists) { |
| 5473 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | ib::error(ER_IB_MSG_294, old_path, new_path, ulong{space_id}); |
| 5474 | 11 | return DB_TABLESPACE_EXISTS; | |
| 5475 | } | ||
| 5476 | |||
| 5477 | 101898 | return DB_SUCCESS; | |
| 5478 | } | ||
| 5479 | |||
| 5480 | /** Rename a single-table tablespace. | ||
| 5481 | The tablespace must exist in the memory cache. | ||
| 5482 | @param[in] space_id Tablespace ID | ||
| 5483 | @param[in] old_path Old file name | ||
| 5484 | @param[in] new_name New tablespace name in the schema/space | ||
| 5485 | @param[in] new_path_in New file name, or nullptr if it is located | ||
| 5486 | in the normal data directory | ||
| 5487 | @return InnoDB error code */ | ||
| 5488 | 79857 | dberr_t Fil_shard::space_rename(space_id_t space_id, const char *old_path, | |
| 5489 | const char *new_name, const char *new_path_in) { | ||
| 5490 | fil_space_t *space; | ||
| 5491 | 79857 | ulint count = 0; | |
| 5492 | 79857 | fil_node_t *file = nullptr; | |
| 5493 | 79857 | bool write_ddl_log = true; | |
| 5494 | 79857 | auto start_time = std::chrono::steady_clock::now(); | |
| 5495 | |||
| 5496 | #ifdef UNIV_DEBUG | ||
| 5497 | static uint32_t crash_injection_rename_tablespace_counter = 1; | ||
| 5498 | #endif /* UNIV_DEBUG */ | ||
| 5499 | |||
| 5500 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79857 times.
|
79857 | ut_a(space_id != TRX_SYS_SPACE); |
| 5501 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79857 times.
|
79857 | ut_ad(strchr(new_name, '/') != nullptr); |
| 5502 | |||
| 5503 | for (;;) { | ||
| 5504 | 160072 | bool retry = false; | |
| 5505 | 160072 | bool flush = false; | |
| 5506 | |||
| 5507 | 160072 | ++count; | |
| 5508 | |||
| 5509 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 160072 times.
|
160072 | if (!(count % 1000)) { |
| 5510 | ✗ | ib::warn(ER_IB_MSG_295, old_path, ulong{space_id}, ulonglong{count}); | |
| 5511 | } | ||
| 5512 | |||
| 5513 | /* The name map and space ID map are in the same shard. */ | ||
| 5514 |
1/2✓ Branch 0 taken 160072 times.
✗ Branch 1 not taken.
|
160072 | mutex_acquire(); |
| 5515 | |||
| 5516 |
1/2✓ Branch 0 taken 160072 times.
✗ Branch 1 not taken.
|
160072 | space = get_space_by_id(space_id); |
| 5517 | |||
| 5518 |
3/4✓ Branch 0 taken 160072 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 160071 times.
|
160072 | DBUG_EXECUTE_IF("fil_rename_tablespace_failure_1", space = nullptr;); |
| 5519 | |||
| 5520 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 160071 times.
|
160072 | if (space == nullptr) { |
| 5521 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | ib::error(ER_IB_MSG_296, ulong{space_id}, old_path); |
| 5522 | |||
| 5523 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | mutex_release(); |
| 5524 | |||
| 5525 | 1 | return DB_ERROR; | |
| 5526 | |||
| 5527 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 160071 times.
|
160071 | } else if (space->prevent_file_open) { |
| 5528 | /* Some other thread has stopped the IO. We need to | ||
| 5529 | wait for the other thread to complete its operation. */ | ||
| 5530 | ✗ | mutex_release(); | |
| 5531 | |||
| 5532 | ✗ | if (std::chrono::steady_clock::now() - start_time >= PRINT_INTERVAL) { | |
| 5533 | ✗ | ib::warn(ER_IB_MSG_297); | |
| 5534 | |||
| 5535 | ✗ | start_time = std::chrono::steady_clock::now(); | |
| 5536 | } | ||
| 5537 | |||
| 5538 | ✗ | std::this_thread::sleep_for(std::chrono::seconds(1)); | |
| 5539 | |||
| 5540 | ✗ | continue; | |
| 5541 | |||
| 5542 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 160071 times.
|
160071 | } else if (count > 25000) { |
| 5543 | ✗ | mutex_release(); | |
| 5544 | |||
| 5545 | ✗ | return DB_ERROR; | |
| 5546 | |||
| 5547 |
2/4✓ Branch 0 taken 160071 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 160071 times.
|
160071 | } else if (space != get_space_by_name(space->name)) { |
| 5548 | ✗ | ib::error(ER_IB_MSG_298, space->name); | |
| 5549 | |||
| 5550 | ✗ | mutex_release(); | |
| 5551 | |||
| 5552 | ✗ | return DB_ERROR; | |
| 5553 | |||
| 5554 | } else { | ||
| 5555 |
1/2✓ Branch 0 taken 160071 times.
✗ Branch 1 not taken.
|
160071 | auto new_space = get_space_by_name(new_name); |
| 5556 | |||
| 5557 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 160071 times.
|
160071 | if (new_space != nullptr) { |
| 5558 | ✗ | if (new_space == space) { | |
| 5559 | ✗ | mutex_release(); | |
| 5560 | |||
| 5561 | ✗ | return DB_SUCCESS; | |
| 5562 | } | ||
| 5563 | |||
| 5564 | ✗ | ut_a(new_space->id == space->id); | |
| 5565 | } | ||
| 5566 | } | ||
| 5567 | |||
| 5568 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 160071 times.
|
160071 | ut_a(space->files.size() == 1); |
| 5569 | |||
| 5570 | #ifndef UNIV_HOTBACKUP | ||
| 5571 | /* Don't write DDL log during recovery when log_ddl is | ||
| 5572 | not initialized. */ | ||
| 5573 | |||
| 5574 |
3/4✓ Branch 0 taken 79856 times.
✓ Branch 1 taken 80215 times.
✓ Branch 2 taken 79856 times.
✗ Branch 3 not taken.
|
160071 | if (write_ddl_log && log_ddl != nullptr) { |
| 5575 | /* Write ddl log when space->prevent_file_open is true | ||
| 5576 | can cause deadlock: | ||
| 5577 | a. buffer flush thread waits for rename thread to set | ||
| 5578 | prevent_file_open to false; | ||
| 5579 | b. rename thread waits for buffer flush thread to flush | ||
| 5580 | a page and release page lock. The page is ready for | ||
| 5581 | flush in double write buffer. */ | ||
| 5582 | |||
| 5583 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79856 times.
|
79856 | ut_ad(!space->prevent_file_open); |
| 5584 | |||
| 5585 | 79856 | file = &space->files.front(); | |
| 5586 | |||
| 5587 | char *new_file_name = new_path_in == nullptr | ||
| 5588 |
2/12✗ Branch 0 not taken.
✓ Branch 1 taken 79856 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 79856 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
159712 | ? Fil_path::make_ibd_from_table_name(new_name) |
| 5589 |
2/4✓ Branch 0 taken 79856 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79856 times.
|
79856 | : mem_strdup(new_path_in); |
| 5590 | |||
| 5591 | 79856 | char *old_file_name = file->name; | |
| 5592 | |||
| 5593 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79856 times.
|
79856 | ut_ad(strchr(old_file_name, OS_PATH_SEPARATOR) != nullptr); |
| 5594 | |||
| 5595 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79856 times.
|
79856 | ut_ad(strchr(new_file_name, OS_PATH_SEPARATOR) != nullptr); |
| 5596 | |||
| 5597 |
1/2✓ Branch 0 taken 79856 times.
✗ Branch 1 not taken.
|
79856 | mutex_release(); |
| 5598 | |||
| 5599 | /* Rename ddl log is for rollback, so we exchange | ||
| 5600 | old file name with new file name. */ | ||
| 5601 |
1/2✓ Branch 0 taken 79722 times.
✗ Branch 1 not taken.
|
79856 | dberr_t err = log_ddl->write_rename_space_log(space_id, new_file_name, |
| 5602 | old_file_name); | ||
| 5603 | 79722 | ut::free(new_file_name); | |
| 5604 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 79720 times.
|
79722 | if (err != DB_SUCCESS) { |
| 5605 | 2 | return err; | |
| 5606 | } | ||
| 5607 | |||
| 5608 | 79720 | write_ddl_log = false; | |
| 5609 | 79720 | continue; | |
| 5610 | 79720 | } | |
| 5611 | #endif /* !UNIV_HOTBACKUP */ | ||
| 5612 | |||
| 5613 | /* We temporarily close the .ibd file because we do | ||
| 5614 | not trust that operating systems can rename an open | ||
| 5615 | file. For the closing we have to wait until there | ||
| 5616 | are no pending I/O's or flushes on the file. */ | ||
| 5617 | |||
| 5618 | 80215 | space->prevent_file_open = true; | |
| 5619 | |||
| 5620 | 80215 | file = &space->files.front(); | |
| 5621 | |||
| 5622 |
4/4✓ Branch 0 taken 80172 times.
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 79900 times.
✓ Branch 3 taken 272 times.
|
80215 | if (file->n_pending_ios > 0 || file->n_pending_flushes > 0 || |
| 5623 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79900 times.
|
79900 | file->is_being_extended) { |
| 5624 | /* There are pending I/O's or flushes or the | ||
| 5625 | file is currently being extended, sleep for | ||
| 5626 | a while and retry */ | ||
| 5627 | |||
| 5628 | 315 | retry = true; | |
| 5629 | |||
| 5630 | 315 | space->prevent_file_open = false; | |
| 5631 | |||
| 5632 |
3/4✓ Branch 0 taken 79900 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 180 times.
✓ Branch 3 taken 79720 times.
|
79900 | } else if (!file->is_flushed()) { |
| 5633 | /* Flush the space */ | ||
| 5634 | |||
| 5635 | 180 | retry = flush = true; | |
| 5636 | |||
| 5637 | 180 | space->prevent_file_open = false; | |
| 5638 | |||
| 5639 |
2/2✓ Branch 0 taken 39883 times.
✓ Branch 1 taken 39837 times.
|
79720 | } else if (file->is_open) { |
| 5640 |
1/2✓ Branch 0 taken 39883 times.
✗ Branch 1 not taken.
|
39883 | close_file(file); |
| 5641 | } | ||
| 5642 | |||
| 5643 |
2/2✓ Branch 0 taken 79720 times.
✓ Branch 1 taken 495 times.
|
80215 | if (!retry) { |
| 5644 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79720 times.
|
79720 | ut_ad(space->prevent_file_open); |
| 5645 | } | ||
| 5646 | |||
| 5647 |
1/2✓ Branch 0 taken 80215 times.
✗ Branch 1 not taken.
|
80215 | mutex_release(); |
| 5648 | |||
| 5649 |
2/2✓ Branch 0 taken 79720 times.
✓ Branch 1 taken 495 times.
|
80215 | if (!retry) { |
| 5650 | 79720 | break; | |
| 5651 | } | ||
| 5652 | |||
| 5653 |
1/2✓ Branch 0 taken 495 times.
✗ Branch 1 not taken.
|
495 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
| 5654 | |||
| 5655 |
2/2✓ Branch 0 taken 180 times.
✓ Branch 1 taken 315 times.
|
495 | if (flush) { |
| 5656 |
1/2✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
|
180 | mutex_acquire(); |
| 5657 | |||
| 5658 |
1/2✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
|
180 | space_flush(space->id); |
| 5659 | |||
| 5660 |
1/2✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
|
180 | mutex_release(); |
| 5661 | } | ||
| 5662 | 80215 | } | |
| 5663 | |||
| 5664 | #ifndef UNIV_HOTBACKUP | ||
| 5665 | /* Make sure we re not holding shard mutex. */ | ||
| 5666 |
2/4✓ Branch 0 taken 79720 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79720 times.
|
79720 | ut_ad(!mutex_owned()); |
| 5667 |
1/2✓ Branch 0 taken 79720 times.
✗ Branch 1 not taken.
|
79720 | Clone_notify notifier(Clone_notify::Type::SPACE_RENAME, space_id, false); |
| 5668 | |||
| 5669 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 79718 times.
|
79720 | if (notifier.failed()) { |
| 5670 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | mutex_acquire(); |
| 5671 | 2 | space->prevent_file_open = false; | |
| 5672 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | mutex_release(); |
| 5673 | |||
| 5674 | 2 | return DB_ERROR; | |
| 5675 | } | ||
| 5676 | #endif /* !UNIV_HOTBACKUP */ | ||
| 5677 | |||
| 5678 | char *new_file_name; | ||
| 5679 | |||
| 5680 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79718 times.
|
79718 | if (new_path_in == nullptr) { |
| 5681 | ✗ | new_file_name = Fil_path::make_ibd_from_table_name(new_name); | |
| 5682 | } else { | ||
| 5683 |
1/2✓ Branch 0 taken 79718 times.
✗ Branch 1 not taken.
|
79718 | new_file_name = mem_strdup(new_path_in); |
| 5684 | } | ||
| 5685 | |||
| 5686 | 79718 | char *old_file_name = file->name; | |
| 5687 | 79718 | char *old_space_name = space->name; | |
| 5688 |
1/2✓ Branch 0 taken 79718 times.
✗ Branch 1 not taken.
|
79718 | char *new_space_name = mem_strdup(new_name); |
| 5689 | |||
| 5690 | #ifndef UNIV_HOTBACKUP | ||
| 5691 |
1/2✓ Branch 0 taken 79718 times.
✗ Branch 1 not taken.
|
79718 | if (!recv_recovery_on) { |
| 5692 |
1/2✓ Branch 0 taken 79718 times.
✗ Branch 1 not taken.
|
79718 | mtr_t mtr; |
| 5693 | |||
| 5694 |
1/2✓ Branch 0 taken 79718 times.
✗ Branch 1 not taken.
|
79718 | mtr.start(); |
| 5695 | |||
| 5696 |
1/2✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
|
79718 | fil_name_write_rename(space_id, old_file_name, new_file_name, &mtr); |
| 5697 | |||
| 5698 |
1/2✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
|
79717 | mtr.commit(); |
| 5699 | 79717 | } | |
| 5700 | #endif /* !UNIV_HOTBACKUP */ | ||
| 5701 | |||
| 5702 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79717 times.
|
79717 | ut_ad(strchr(old_file_name, OS_PATH_SEPARATOR) != nullptr); |
| 5703 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79717 times.
|
79717 | ut_ad(strchr(new_file_name, OS_PATH_SEPARATOR) != nullptr); |
| 5704 | |||
| 5705 |
1/2✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
|
79717 | mutex_acquire(); |
| 5706 | |||
| 5707 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79717 times.
|
79717 | ut_ad(space->prevent_file_open); |
| 5708 | |||
| 5709 | /* We already checked these. */ | ||
| 5710 |
2/4✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79717 times.
|
79717 | ut_ad(space == get_space_by_name(old_space_name)); |
| 5711 |
2/4✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79717 times.
|
79717 | ut_ad(get_space_by_name(new_space_name) == nullptr); |
| 5712 | |||
| 5713 | bool success; | ||
| 5714 | |||
| 5715 |
3/4✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 79716 times.
|
79717 | DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2", goto skip_rename;); |
| 5716 | |||
| 5717 |
2/6✓ Branch 0 taken 79716 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79716 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
79716 | DBUG_INJECT_CRASH("ddl_crash_before_rename_tablespace", |
| 5718 | crash_injection_rename_tablespace_counter++); | ||
| 5719 | |||
| 5720 | 79716 | file = &space->files.front(); | |
| 5721 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79716 times.
|
79716 | ut_ad(!file->is_open); |
| 5722 | |||
| 5723 |
1/2✓ Branch 0 taken 79716 times.
✗ Branch 1 not taken.
|
79716 | success = os_file_rename(innodb_data_file_key, old_file_name, new_file_name); |
| 5724 | |||
| 5725 |
2/4✓ Branch 0 taken 79716 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79716 times.
|
79717 | DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2", skip_rename |
| 5726 | : success = false;); | ||
| 5727 | |||
| 5728 |
2/6✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79717 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
79717 | DBUG_INJECT_CRASH("ddl_crash_after_rename_tablespace", |
| 5729 | crash_injection_rename_tablespace_counter++); | ||
| 5730 | |||
| 5731 |
2/2✓ Branch 0 taken 79716 times.
✓ Branch 1 taken 1 times.
|
79717 | if (success) { |
| 5732 | 79716 | file->name = new_file_name; | |
| 5733 | |||
| 5734 |
1/2✓ Branch 0 taken 79716 times.
✗ Branch 1 not taken.
|
79716 | update_space_name_map(space, new_space_name); |
| 5735 | |||
| 5736 | 79716 | space->name = new_space_name; | |
| 5737 | |||
| 5738 | } else { | ||
| 5739 | /* Because nothing was renamed, we must free the new | ||
| 5740 | names, not the old ones. */ | ||
| 5741 | 1 | old_file_name = new_file_name; | |
| 5742 | 1 | old_space_name = new_space_name; | |
| 5743 | } | ||
| 5744 | |||
| 5745 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79717 times.
|
79717 | ut_ad(space->prevent_file_open); |
| 5746 | 79717 | space->prevent_file_open = false; | |
| 5747 | |||
| 5748 |
1/2✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
|
79717 | mutex_release(); |
| 5749 | |||
| 5750 | 79717 | ut::free(old_file_name); | |
| 5751 | 79717 | ut::free(old_space_name); | |
| 5752 | |||
| 5753 |
2/2✓ Branch 0 taken 79716 times.
✓ Branch 1 taken 1 times.
|
79717 | return success ? DB_SUCCESS : DB_ERROR; |
| 5754 | 79719 | } | |
| 5755 | |||
| 5756 | /** Rename a single-table tablespace. | ||
| 5757 | The tablespace must exist in the memory cache. | ||
| 5758 | @param[in] space_id Tablespace ID | ||
| 5759 | @param[in] old_path Old file name | ||
| 5760 | @param[in] new_name New tablespace name in the schema/name format | ||
| 5761 | @param[in] new_path_in New file name, or nullptr if it is located in | ||
| 5762 | the normal data directory | ||
| 5763 | @return InnoDB error code */ | ||
| 5764 | 79857 | dberr_t fil_rename_tablespace(space_id_t space_id, const char *old_path, | |
| 5765 | const char *new_name, const char *new_path_in) { | ||
| 5766 | 79857 | auto shard = fil_system->shard_by_id(space_id); | |
| 5767 | |||
| 5768 | 79857 | dberr_t err = shard->space_rename(space_id, old_path, new_name, new_path_in); | |
| 5769 | |||
| 5770 | 79722 | return err; | |
| 5771 | } | ||
| 5772 | |||
| 5773 | /** Rename a tablespace. Use the space_id to find the shard. | ||
| 5774 | @param[in] space_id tablespace ID | ||
| 5775 | @param[in] old_name old tablespace name | ||
| 5776 | @param[in] new_name new tablespace name | ||
| 5777 | @return DB_SUCCESS on success */ | ||
| 5778 | 78 | dberr_t Fil_system::rename_tablespace_name(space_id_t space_id, | |
| 5779 | const char *old_name, | ||
| 5780 | const char *new_name) { | ||
| 5781 | 78 | auto old_shard = fil_system->shard_by_id(space_id); | |
| 5782 | |||
| 5783 | 78 | old_shard->mutex_acquire(); | |
| 5784 | |||
| 5785 | 78 | auto old_space = old_shard->get_space_by_id(space_id); | |
| 5786 | |||
| 5787 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
|
78 | if (old_space == nullptr) { |
| 5788 | ✗ | old_shard->mutex_release(); | |
| 5789 | |||
| 5790 | ✗ | ib::error(ER_IB_MSG_299, old_name); | |
| 5791 | |||
| 5792 | ✗ | return DB_TABLESPACE_NOT_FOUND; | |
| 5793 | } | ||
| 5794 | |||
| 5795 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
|
78 | ut_ad(old_space == old_shard->get_space_by_name(old_name)); |
| 5796 | 78 | old_shard->mutex_release(); | |
| 5797 | |||
| 5798 | 78 | Fil_shard *new_shard{}; | |
| 5799 | 78 | fil_space_t *new_space{}; | |
| 5800 | |||
| 5801 | 78 | mutex_acquire_all(); | |
| 5802 | |||
| 5803 |
2/2✓ Branch 0 taken 5304 times.
✓ Branch 1 taken 78 times.
|
5382 | for (auto shard : m_shards) { |
| 5804 |
1/2✓ Branch 0 taken 5304 times.
✗ Branch 1 not taken.
|
5304 | new_space = shard->get_space_by_name(new_name); |
| 5805 | |||
| 5806 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5304 times.
|
5304 | if (new_space != nullptr) { |
| 5807 | ✗ | new_shard = shard; | |
| 5808 | ✗ | break; | |
| 5809 | } | ||
| 5810 | } | ||
| 5811 | |||
| 5812 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
|
78 | if (new_space != nullptr) { |
| 5813 | ✗ | mutex_release_all(); | |
| 5814 | |||
| 5815 | ✗ | if (new_space->id != old_space->id) { | |
| 5816 | ✗ | ib::error(ER_IB_MSG_300, new_name); | |
| 5817 | |||
| 5818 | ✗ | return DB_TABLESPACE_EXISTS; | |
| 5819 | } else { | ||
| 5820 | ✗ | ut_a(new_shard == old_shard); | |
| 5821 | } | ||
| 5822 | |||
| 5823 | ✗ | return DB_SUCCESS; | |
| 5824 | } | ||
| 5825 | |||
| 5826 | 78 | auto new_space_name = mem_strdup(new_name); | |
| 5827 | 78 | auto old_space_name = old_space->name; | |
| 5828 | |||
| 5829 | 78 | old_shard->update_space_name_map(old_space, new_space_name); | |
| 5830 | |||
| 5831 | 78 | old_space->name = new_space_name; | |
| 5832 | |||
| 5833 | 78 | mutex_release_all(); | |
| 5834 | |||
| 5835 | 78 | ut::free(old_space_name); | |
| 5836 | |||
| 5837 | 78 | return DB_SUCCESS; | |
| 5838 | } | ||
| 5839 | |||
| 5840 | 78 | dberr_t fil_rename_tablespace_by_id(space_id_t space_id, const char *old_name, | |
| 5841 | const char *new_name) { | ||
| 5842 | 78 | return fil_system->rename_tablespace_name(space_id, old_name, new_name); | |
| 5843 | } | ||
| 5844 | |||
| 5845 | 294623 | dberr_t fil_write_initial_pages(pfs_os_file_t file, const char *path, | |
| 5846 | fil_type_t type [[maybe_unused]], | ||
| 5847 | page_no_t size, const byte *encrypt_info, | ||
| 5848 | space_id_t space_id, uint32_t &space_flags, | ||
| 5849 | bool &atomic_write, bool &punch_hole) { | ||
| 5850 | 294623 | bool success = false; | |
| 5851 | 294623 | atomic_write = false; | |
| 5852 | 294623 | punch_hole = false; | |
| 5853 | |||
| 5854 |
1/2✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
|
294623 | const page_size_t page_size(space_flags); |
| 5855 |
1/2✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
|
294623 | const auto sz = ulonglong{size * page_size.physical()}; |
| 5856 | |||
| 5857 | #if !defined(NO_FALLOCATE) && defined(UNIV_LINUX) | ||
| 5858 | { | ||
| 5859 | 294623 | int ret = 0; | |
| 5860 | #ifdef UNIV_DEBUG | ||
| 5861 |
3/4✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 294613 times.
|
294623 | DBUG_EXECUTE_IF("fil_create_temp_tablespace_fail_fallocate", ret = -1;); |
| 5862 |
2/2✓ Branch 0 taken 294613 times.
✓ Branch 1 taken 10 times.
|
294623 | if (ret == 0) |
| 5863 | #endif /* UNIV_DEBUG */ | ||
| 5864 | { | ||
| 5865 |
1/2✓ Branch 0 taken 294613 times.
✗ Branch 1 not taken.
|
294613 | ret = posix_fallocate(file.m_file, 0, sz); |
| 5866 | } | ||
| 5867 | |||
| 5868 |
2/2✓ Branch 0 taken 294613 times.
✓ Branch 1 taken 10 times.
|
294623 | if (ret == 0) { |
| 5869 | 294613 | success = true; | |
| 5870 |
4/4✓ Branch 0 taken 197923 times.
✓ Branch 1 taken 96690 times.
✓ Branch 2 taken 96690 times.
✓ Branch 3 taken 197923 times.
|
492536 | if (type == FIL_TYPE_TEMPORARY || |
| 5871 |
2/4✓ Branch 0 taken 197923 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 197923 times.
|
197923 | fil_fusionio_enable_atomic_write(file)) { |
| 5872 | 96690 | atomic_write = true; | |
| 5873 | } | ||
| 5874 | } else { | ||
| 5875 | /* If posix_fallocate() fails for any reason, issue only a warning | ||
| 5876 | and then fall back to os_file_set_size() */ | ||
| 5877 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | ib::warn(ER_IB_MSG_303, path, sz, ret, strerror(errno)); |
| 5878 | } | ||
| 5879 | } | ||
| 5880 | #endif /* !NO_FALLOCATE && UNIV_LINUX */ | ||
| 5881 | |||
| 5882 |
6/6✓ Branch 0 taken 294613 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 294580 times.
✓ Branch 3 taken 33 times.
✓ Branch 4 taken 197920 times.
✓ Branch 5 taken 96660 times.
|
294623 | if (!success || (tbsp_extend_and_initialize && !atomic_write)) { |
| 5883 |
1/2✓ Branch 0 taken 197930 times.
✗ Branch 1 not taken.
|
197930 | success = os_file_set_size(path, file, 0, sz, true); |
| 5884 | |||
| 5885 |
1/2✓ Branch 0 taken 197930 times.
✗ Branch 1 not taken.
|
197930 | if (success) { |
| 5886 | /* explicit initialization is needed as same as fil_space_extend(), | ||
| 5887 | instead of punch_hole. */ | ||
| 5888 | dberr_t err = | ||
| 5889 |
2/4✓ Branch 0 taken 197930 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 197930 times.
✗ Branch 3 not taken.
|
197930 | os_file_write_zeros(file, path, page_size.physical(), 0, sz); |
| 5890 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 197930 times.
|
197930 | if (err != DB_SUCCESS) { |
| 5891 | ✗ | ib::warn(ER_IB_MSG_320) << "Error while writing " << sz << " zeroes to " | |
| 5892 | ✗ | << path << " starting at offset " << 0; | |
| 5893 | } | ||
| 5894 | } | ||
| 5895 | } | ||
| 5896 | |||
| 5897 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 294623 times.
|
294623 | if (!success) { |
| 5898 | ✗ | return DB_OUT_OF_DISK_SPACE; | |
| 5899 | } | ||
| 5900 | |||
| 5901 | /* Note: We are actually punching a hole, previous contents will | ||
| 5902 | be lost after this call, if it succeeds. In this case the file | ||
| 5903 | should be full of NULs. */ | ||
| 5904 | |||
| 5905 |
1/2✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
|
294623 | punch_hole = os_is_sparse_file_supported(file); |
| 5906 | |||
| 5907 | /* Should not make large punch hole as initialization of large file, | ||
| 5908 | for crash-recovery safeness around disk-full. */ | ||
| 5909 | |||
| 5910 | /* We have to write the space id to the file immediately and flush the | ||
| 5911 | file to disk. This is because in crash recovery we must be aware what | ||
| 5912 | tablespaces exist and what are their space id's, so that we can apply | ||
| 5913 | the log records to the right file. It may take quite a while until | ||
| 5914 | buffer pool flush algorithms write anything to the file and flush it to | ||
| 5915 | disk. If we would not write here anything, the file would be filled | ||
| 5916 | with zeros from the call of os_file_set_size(), until a buffer pool | ||
| 5917 | flush would write to it. */ | ||
| 5918 | |||
| 5919 | /* Align the memory for file i/o if we might have O_DIRECT set */ | ||
| 5920 | auto page = static_cast<byte *>( | ||
| 5921 |
2/4✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 294623 times.
✗ Branch 3 not taken.
|
294623 | ut::aligned_zalloc(2 * page_size.logical(), page_size.logical())); |
| 5922 | |||
| 5923 | /* Add the UNIV_PAGE_SIZE to the table flags and write them to the | ||
| 5924 | tablespace header. */ | ||
| 5925 |
1/2✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
|
294622 | space_flags = fsp_flags_set_page_size(space_flags, page_size); |
| 5926 |
1/2✓ Branch 0 taken 294622 times.
✗ Branch 1 not taken.
|
294623 | fsp_header_init_fields(page, space_id, space_flags); |
| 5927 |
1/2✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
|
294622 | mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id); |
| 5928 | |||
| 5929 |
1/2✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
|
294623 | mach_write_to_4(page + FIL_PAGE_SRV_VERSION, DD_SPACE_CURRENT_SRV_VERSION); |
| 5930 |
1/2✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
|
294623 | mach_write_to_4(page + FIL_PAGE_SPACE_VERSION, |
| 5931 | DD_SPACE_CURRENT_SPACE_VERSION); | ||
| 5932 | |||
| 5933 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 294603 times.
|
294623 | if (encrypt_info != nullptr) { |
| 5934 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | auto key_offset = fsp_header_get_encryption_offset(page_size); |
| 5935 | 20 | memcpy(page + key_offset, encrypt_info, Encryption::INFO_SIZE); | |
| 5936 | } | ||
| 5937 | |||
| 5938 |
1/2✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
|
294623 | IORequest request(IORequest::WRITE); |
| 5939 | 294623 | dberr_t err = DB_SUCCESS; | |
| 5940 | |||
| 5941 |
2/2✓ Branch 0 taken 293376 times.
✓ Branch 1 taken 1247 times.
|
294623 | if (!page_size.is_compressed()) { |
| 5942 | 293376 | buf_flush_init_for_writing(nullptr, page, nullptr, 0, | |
| 5943 |
2/4✓ Branch 0 taken 293376 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 293376 times.
✗ Branch 3 not taken.
|
293376 | fsp_is_checksum_disabled(space_id), |
| 5944 | true /* skip_lsn_check */); | ||
| 5945 | |||
| 5946 |
2/4✓ Branch 0 taken 293376 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 293376 times.
✗ Branch 3 not taken.
|
293376 | err = os_file_write(request, path, file, page, 0, page_size.physical()); |
| 5947 | |||
| 5948 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 293376 times.
|
293376 | ut_ad(err != DB_IO_NO_PUNCH_HOLE); |
| 5949 | |||
| 5950 | } else { | ||
| 5951 | page_zip_des_t page_zip; | ||
| 5952 | |||
| 5953 |
2/4✓ Branch 0 taken 1247 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1247 times.
✗ Branch 3 not taken.
|
1247 | page_zip_set_size(&page_zip, page_size.physical()); |
| 5954 |
1/2✓ Branch 0 taken 1247 times.
✗ Branch 1 not taken.
|
1247 | page_zip.data = page + page_size.logical(); |
| 5955 | 1247 | ut_d(page_zip.m_start = 0); | |
| 5956 | 1247 | page_zip.m_end = 0; | |
| 5957 | 1247 | page_zip.n_blobs = 0; | |
| 5958 | 1247 | page_zip.m_nonempty = false; | |
| 5959 | |||
| 5960 | 1247 | buf_flush_init_for_writing(nullptr, page, &page_zip, 0, | |
| 5961 |
2/4✓ Branch 0 taken 1247 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1247 times.
✗ Branch 3 not taken.
|
1247 | fsp_is_checksum_disabled(space_id), |
| 5962 | true /* skip_lsn_check */); | ||
| 5963 | |||
| 5964 |
2/4✓ Branch 0 taken 1247 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1247 times.
✗ Branch 3 not taken.
|
1247 | err = os_file_write(request, path, file, page_zip.data, 0, |
| 5965 | page_size.physical()); | ||
| 5966 | |||
| 5967 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1247 times.
|
1247 | ut_a(err != DB_IO_NO_PUNCH_HOLE); |
| 5968 | |||
| 5969 | 1247 | punch_hole = false; | |
| 5970 | } | ||
| 5971 | |||
| 5972 | 294623 | ut::aligned_free(page); | |
| 5973 | 294622 | return err; | |
| 5974 | 294622 | } | |
| 5975 | |||
| 5976 | /** Create a tablespace (an IBD or IBT) file | ||
| 5977 | @param[in] space_id Tablespace ID | ||
| 5978 | @param[in] name Tablespace name in dbname/tablename format. | ||
| 5979 | For general tablespaces, the 'dbname/' part | ||
| 5980 | may be missing. | ||
| 5981 | @param[in] path Path and filename of the datafile to create. | ||
| 5982 | @param[in] flags Tablespace flags | ||
| 5983 | @param[in] size Initial size of the tablespace file in pages, | ||
| 5984 | must be >= FIL_IBD_FILE_INITIAL_SIZE | ||
| 5985 | @param[in] type FIL_TYPE_TABLESPACE or FIL_TYPE_TEMPORARY | ||
| 5986 | @param[in] mode keyring encryption mode | ||
| 5987 | @param[in] keyring_encryption_key_id info on keyring encryption key | ||
| 5988 | @return DB_SUCCESS or error code */ | ||
| 5989 | 294360 | static dberr_t fil_create_tablespace( | |
| 5990 | space_id_t space_id, const char *name, const char *path, uint32_t flags, | ||
| 5991 | page_no_t size, fil_type_t type, const fil_encryption_t mode, | ||
| 5992 | const KeyringEncryptionKeyIdInfo &keyring_encryption_key_id) { | ||
| 5993 | 294360 | fil_space_crypt_t *crypt_data = nullptr; | |
| 5994 | |||
| 5995 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 294360 times.
|
294360 | ut_ad(!fsp_is_system_tablespace(space_id)); |
| 5996 |
2/4✓ Branch 0 taken 294360 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 294360 times.
|
294360 | ut_a(fsp_flags_is_valid(flags)); |
| 5997 |
4/6✓ Branch 0 taken 197660 times.
✓ Branch 1 taken 96700 times.
✓ Branch 2 taken 197660 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 294360 times.
|
294360 | ut_a(type == FIL_TYPE_TEMPORARY || type == FIL_TYPE_TABLESPACE); |
| 5998 | |||
| 5999 | 294360 | bool has_shared_space = FSP_FLAGS_GET_SHARED(flags); | |
| 6000 | /* Create the subdirectories in the path, if they are | ||
| 6001 | not there already. */ | ||
| 6002 |
2/2✓ Branch 0 taken 196494 times.
✓ Branch 1 taken 97866 times.
|
294360 | if (!has_shared_space) { |
| 6003 |
1/2✓ Branch 0 taken 196494 times.
✗ Branch 1 not taken.
|
196494 | auto err = os_file_create_subdirs_if_needed(path); |
| 6004 | |||
| 6005 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 196494 times.
|
196494 | if (err != DB_SUCCESS) { |
| 6006 | ✗ | return err; /* purecov: inspected */ | |
| 6007 | } | ||
| 6008 | } | ||
| 6009 | |||
| 6010 | 294360 | bool success = false; | |
| 6011 | |||
| 6012 |
6/8✓ Branch 0 taken 410 times.
✓ Branch 1 taken 293950 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 410 times.
✓ Branch 4 taken 96700 times.
✓ Branch 5 taken 197660 times.
✓ Branch 6 taken 294360 times.
✗ Branch 7 not taken.
|
294360 | auto file = os_file_create( |
| 6013 | type == FIL_TYPE_TEMPORARY ? innodb_temp_file_key : innodb_data_file_key, | ||
| 6014 | path, OS_FILE_CREATE | OS_FILE_ON_ERROR_NO_EXIT, OS_FILE_NORMAL, | ||
| 6015 | OS_DATA_FILE, srv_read_only_mode && (type != FIL_TYPE_TEMPORARY), | ||
| 6016 | &success); | ||
| 6017 | |||
| 6018 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 294353 times.
|
294360 | if (!success) { |
| 6019 | /* purecov: begin inspected */ | ||
| 6020 | /* The following call will print an error message */ | ||
| 6021 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | ulint error = os_file_get_last_error(true); |
| 6022 | |||
| 6023 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | ib::error(ER_IB_MSG_301, path); |
| 6024 | |||
| 6025 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
|
7 | switch (error) { |
| 6026 | ✗ | case OS_FILE_ALREADY_EXISTS: | |
| 6027 | #ifndef UNIV_HOTBACKUP | ||
| 6028 | ✗ | ib::error(ER_IB_MSG_UNEXPECTED_FILE_EXISTS, path, path); | |
| 6029 | ✗ | return DB_TABLESPACE_EXISTS; | |
| 6030 | #else /* !UNIV_HOTBACKUP */ | ||
| 6031 | return DB_SUCCESS; /* Already existing file not an error here. */ | ||
| 6032 | #endif /* !UNIV_HOTBACKUP */ | ||
| 6033 | |||
| 6034 | ✗ | case OS_FILE_NAME_TOO_LONG: | |
| 6035 | ✗ | ib::error(ER_IB_MSG_TOO_LONG_PATH, path); | |
| 6036 | ✗ | return DB_TOO_LONG_PATH; | |
| 6037 | |||
| 6038 | ✗ | case OS_FILE_DISK_FULL: | |
| 6039 | ✗ | return DB_OUT_OF_DISK_SPACE; | |
| 6040 | |||
| 6041 | 7 | default: | |
| 6042 | 7 | return DB_ERROR; | |
| 6043 | } | ||
| 6044 | /* purecov: end */ | ||
| 6045 | } | ||
| 6046 | |||
| 6047 | 294353 | bool atomic_write = false; | |
| 6048 | 294353 | bool punch_hole = false; | |
| 6049 | |||
| 6050 |
1/2✓ Branch 0 taken 294352 times.
✗ Branch 1 not taken.
|
294353 | auto err = fil_write_initial_pages(file, path, type, size, nullptr, space_id, |
| 6051 | flags, atomic_write, punch_hole); | ||
| 6052 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 294352 times.
|
294352 | if (err != DB_SUCCESS) { |
| 6053 | ✗ | ib::error(ER_IB_MSG_304, path); | |
| 6054 | |||
| 6055 | ✗ | os_file_close(file); | |
| 6056 | ✗ | os_file_delete(innodb_data_file_key, path); | |
| 6057 | |||
| 6058 | ✗ | return err; | |
| 6059 | } | ||
| 6060 | |||
| 6061 |
1/2✓ Branch 0 taken 294352 times.
✗ Branch 1 not taken.
|
294352 | success = os_file_flush(file); |
| 6062 | |||
| 6063 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 294352 times.
|
294352 | if (!success) { |
| 6064 | ✗ | ib::error(ER_IB_MSG_305, path); | |
| 6065 | |||
| 6066 | ✗ | os_file_close(file); | |
| 6067 | ✗ | os_file_delete(innodb_data_file_key, path); | |
| 6068 | ✗ | return DB_ERROR; | |
| 6069 | } | ||
| 6070 | |||
| 6071 | #ifndef UNIV_HOTBACKUP | ||
| 6072 | /* Notifier block covers space creation and initialization. */ | ||
| 6073 |
1/2✓ Branch 0 taken 294353 times.
✗ Branch 1 not taken.
|
588705 | Clone_notify notifier(Clone_notify::Type::SPACE_CREATE, space_id, false); |
| 6074 | |||
| 6075 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 294349 times.
|
294353 | if (notifier.failed()) { |
| 6076 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | os_file_close(file); |
| 6077 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | fil_space_destroy_crypt_data(&crypt_data); |
| 6078 | 4 | return DB_ERROR; | |
| 6079 | } | ||
| 6080 | #endif /* !UNIV_HOTBACKUP */ | ||
| 6081 | |||
| 6082 |
1/2✓ Branch 0 taken 294349 times.
✗ Branch 1 not taken.
|
294349 | auto space = fil_space_create(name, space_id, flags, type, crypt_data, mode); |
| 6083 | |||
| 6084 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 294349 times.
|
294349 | if (space == nullptr) { |
| 6085 | ✗ | os_file_close(file); | |
| 6086 | ✗ | os_file_delete(innodb_data_file_key, path); | |
| 6087 | |||
| 6088 | ✗ | return DB_ERROR; | |
| 6089 | } | ||
| 6090 | |||
| 6091 |
3/4✓ Branch 0 taken 286279 times.
✓ Branch 1 taken 8070 times.
✓ Branch 2 taken 286279 times.
✗ Branch 3 not taken.
|
294349 | DEBUG_SYNC_C("fil_ibd_created_space"); |
| 6092 | |||
| 6093 |
1/2✓ Branch 0 taken 294349 times.
✗ Branch 1 not taken.
|
294349 | auto shard = fil_system->shard_by_id(space_id); |
| 6094 | |||
| 6095 | fil_node_t *file_node = | ||
| 6096 |
1/2✓ Branch 0 taken 294349 times.
✗ Branch 1 not taken.
|
294349 | shard->create_node(path, size, space, false, punch_hole, atomic_write); |
| 6097 | |||
| 6098 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 294349 times.
|
294349 | err = (file_node == nullptr) ? DB_ERROR : DB_SUCCESS; |
| 6099 | |||
| 6100 | #ifndef UNIV_HOTBACKUP | ||
| 6101 | /* Temporary tablespace creation need not be redo logged */ | ||
| 6102 |
3/4✓ Branch 0 taken 294349 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 197649 times.
✓ Branch 3 taken 96700 times.
|
294349 | if (err == DB_SUCCESS && type != FIL_TYPE_TEMPORARY) { |
| 6103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 197649 times.
|
197649 | ut_a(space->files.size() == 1); |
| 6104 | 197649 | const auto &file = space->files.front(); | |
| 6105 | |||
| 6106 |
1/2✓ Branch 0 taken 197649 times.
✗ Branch 1 not taken.
|
197649 | mtr_t mtr; |
| 6107 | |||
| 6108 |
1/2✓ Branch 0 taken 197649 times.
✗ Branch 1 not taken.
|
197649 | mtr_start(&mtr); |
| 6109 | |||
| 6110 |
1/2✓ Branch 0 taken 197649 times.
✗ Branch 1 not taken.
|
197649 | fil_op_write_log(MLOG_FILE_CREATE, space_id, file.name, nullptr, |
| 6111 | space->flags, &mtr); | ||
| 6112 | |||
| 6113 |
1/2✓ Branch 0 taken 197649 times.
✗ Branch 1 not taken.
|
197649 | mtr_commit(&mtr); |
| 6114 | |||
| 6115 |
4/6✓ Branch 0 taken 197649 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 197648 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
197649 | DBUG_EXECUTE_IF("fil_ibd_create_log", log_make_latest_checkpoint();); |
| 6116 | 197649 | } | |
| 6117 | |||
| 6118 | #endif /* !UNIV_HOTBACKUP */ | ||
| 6119 | |||
| 6120 | /* For encryption tablespace, initial encryption information. */ | ||
| 6121 |
5/6✓ Branch 0 taken 294349 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1556 times.
✓ Branch 3 taken 292793 times.
✓ Branch 4 taken 1556 times.
✓ Branch 5 taken 292793 times.
|
588698 | if (space != nullptr && |
| 6122 | 294349 | (FSP_FLAGS_GET_ENCRYPTION(space->flags))) { | |
| 6123 |
1/2✓ Branch 0 taken 1556 times.
✗ Branch 1 not taken.
|
1556 | err = fil_set_encryption( |
| 6124 | space->id, | ||
| 6125 | Encryption::AES, nullptr, | ||
| 6126 | nullptr); | ||
| 6127 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1556 times.
|
1556 | ut_ad(err == DB_SUCCESS); |
| 6128 | } | ||
| 6129 | |||
| 6130 | 294349 | space->encryption_op_in_progress = Encryption::Progress::NONE; | |
| 6131 | |||
| 6132 |
1/2✓ Branch 0 taken 294349 times.
✗ Branch 1 not taken.
|
294349 | os_file_close(file); |
| 6133 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 294349 times.
|
294349 | if (err != DB_SUCCESS) { |
| 6134 | ✗ | os_file_delete(innodb_data_file_key, path); | |
| 6135 | } | ||
| 6136 | |||
| 6137 | 294349 | return err; | |
| 6138 | } | ||
| 6139 | |||
| 6140 | 197660 | dberr_t fil_ibd_create( | |
| 6141 | space_id_t space_id, const char *name, const char *path, uint32_t flags, | ||
| 6142 | page_no_t size, const fil_encryption_t mode, | ||
| 6143 | const KeyringEncryptionKeyIdInfo &keyring_encryption_key_id) { | ||
| 6144 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 197660 times.
|
197660 | ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE); |
| 6145 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 197660 times.
|
197660 | ut_ad(!srv_read_only_mode); |
| 6146 | 197660 | return fil_create_tablespace(space_id, name, path, flags, size, | |
| 6147 | FIL_TYPE_TABLESPACE, mode, | ||
| 6148 | 197660 | keyring_encryption_key_id); | |
| 6149 | } | ||
| 6150 | |||
| 6151 | 96700 | dberr_t fil_ibt_create(space_id_t space_id, const char *name, const char *path, | |
| 6152 | uint32_t flags, page_no_t size) { | ||
| 6153 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 96700 times.
|
96700 | ut_a(size >= FIL_IBT_FILE_INITIAL_SIZE); |
| 6154 |
1/2✓ Branch 0 taken 96700 times.
✗ Branch 1 not taken.
|
96700 | return fil_create_tablespace(space_id, name, path, flags, size, |
| 6155 | FIL_TYPE_TEMPORARY, FIL_ENCRYPTION_DEFAULT, | ||
| 6156 | 193400 | KeyringEncryptionKeyIdInfo()); | |
| 6157 | } | ||
| 6158 | |||
| 6159 | #ifndef UNIV_HOTBACKUP | ||
| 6160 | 53899 | dberr_t fil_ibd_open(bool validate, fil_type_t purpose, space_id_t space_id, | |
| 6161 | uint32_t flags, const char *space_name, | ||
| 6162 | const char *path_in, bool strict, bool old_space, | ||
| 6163 | Keyring_encryption_info &keyring_encryption_info) { | ||
| 6164 | 53899 | Datafile df; | |
| 6165 | 53899 | bool is_encrypted = FSP_FLAGS_GET_ENCRYPTION(flags); | |
| 6166 | 53899 | bool for_import = (purpose == FIL_TYPE_IMPORT); | |
| 6167 | |||
| 6168 |
3/4✓ Branch 0 taken 53899 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 53897 times.
|
53899 | if (!fsp_flags_is_valid(flags)) { |
| 6169 | 2 | return DB_CORRUPTION; | |
| 6170 | } | ||
| 6171 | |||
| 6172 | /* Check if the file is already open. The space can be loaded | ||
| 6173 | via fil_space_get_first_path() on startup. This is a problem | ||
| 6174 | for partitioning code. It's a convoluted call graph via the DD. | ||
| 6175 | On Windows this can lead to a sharing violation when we attempt | ||
| 6176 | to open it again. */ | ||
| 6177 | |||
| 6178 |
1/2✓ Branch 0 taken 53897 times.
✗ Branch 1 not taken.
|
53897 | auto shard = fil_system->shard_by_id(space_id); |
| 6179 | |||
| 6180 |
1/2✓ Branch 0 taken 53897 times.
✗ Branch 1 not taken.
|
53897 | shard->mutex_acquire(); |
| 6181 | |||
| 6182 |
1/2✓ Branch 0 taken 53897 times.
✗ Branch 1 not taken.
|
53897 | auto space = shard->get_space_by_id(space_id); |
| 6183 | |||
| 6184 |
1/2✓ Branch 0 taken 53897 times.
✗ Branch 1 not taken.
|
53897 | shard->mutex_release(); |
| 6185 | |||
| 6186 |
1/2✓ Branch 0 taken 53897 times.
✗ Branch 1 not taken.
|
53897 | df.init(space_name, flags); |
| 6187 | |||
| 6188 |
2/2✓ Branch 0 taken 150 times.
✓ Branch 1 taken 53747 times.
|
53897 | if (path_in == nullptr) { |
| 6189 |
1/2✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
|
150 | df.make_filepath(nullptr, space_name, IBD); |
| 6190 | } else { | ||
| 6191 |
1/2✓ Branch 0 taken 53747 times.
✗ Branch 1 not taken.
|
53747 | df.set_filepath(path_in); |
| 6192 | } | ||
| 6193 | |||
| 6194 | /* Attempt to open the tablespace. */ | ||
| 6195 |
3/4✓ Branch 0 taken 53897 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 53871 times.
✓ Branch 3 taken 26 times.
|
53897 | if (df.open_read_only(strict) == DB_SUCCESS) { |
| 6196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 53871 times.
|
53871 | ut_ad(df.is_open()); |
| 6197 | } else { | ||
| 6198 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | ut_ad(!df.is_open()); |
| 6199 | 26 | return DB_CANNOT_OPEN_FILE; | |
| 6200 | } | ||
| 6201 | |||
| 6202 | #if !defined(NO_FALLOCATE) && defined(UNIV_LINUX) | ||
| 6203 | const bool atomic_write = | ||
| 6204 |
5/8✓ Branch 0 taken 445 times.
✓ Branch 1 taken 53426 times.
✓ Branch 2 taken 445 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 445 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 445 times.
|
53871 | !dblwr::is_enabled() && fil_fusionio_enable_atomic_write(df.handle()); |
| 6205 | #else | ||
| 6206 | const bool atomic_write = false; | ||
| 6207 | #endif /* !NO_FALLOCATE && UNIV_LINUX */ | ||
| 6208 | |||
| 6209 | 53871 | Datafile::ValidateOutput validate_output; | |
| 6210 | |||
| 6211 |
6/6✓ Branch 0 taken 34885 times.
✓ Branch 1 taken 18986 times.
✓ Branch 2 taken 374 times.
✓ Branch 3 taken 34511 times.
✓ Branch 4 taken 105 times.
✓ Branch 5 taken 53766 times.
|
73231 | if ((validate || is_encrypted) && |
| 6212 |
1/2✓ Branch 0 taken 19360 times.
✗ Branch 1 not taken.
|
19360 | (validate_output = df.validate_to_dd(space_id, flags, for_import)) |
| 6213 |
2/2✓ Branch 0 taken 105 times.
✓ Branch 1 taken 19255 times.
|
19360 | .error != DB_SUCCESS) { |
| 6214 | /* We don't reply the rename via the redo log anymore. | ||
| 6215 | Therefore we can get a space ID mismatch when validating | ||
| 6216 | the files during bootstrap. */ | ||
| 6217 | |||
| 6218 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
|
105 | if (validate_output.keyring_encryption_info.page0_has_crypt_data) |
| 6219 | ✗ | keyring_encryption_info = validate_output.keyring_encryption_info; | |
| 6220 | |||
| 6221 |
3/4✓ Branch 0 taken 26 times.
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
|
105 | if (!is_encrypted && validate_output.error != DB_WRONG_FILE_NAME) { |
| 6222 | /* The following call prints an error message. | ||
| 6223 | For encrypted tablespace we skip print, since it should | ||
| 6224 | be keyring plugin issues. */ | ||
| 6225 | |||
| 6226 | ✗ | os_file_get_last_error(true); | |
| 6227 | |||
| 6228 | ✗ | ib::error(ER_IB_MSG_306, space_name, TROUBLESHOOT_DATADICT_MSG); | |
| 6229 | } | ||
| 6230 | |||
| 6231 | 105 | return validate_output.error; | |
| 6232 | } | ||
| 6233 | |||
| 6234 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 53766 times.
|
53766 | if (validate_output.keyring_encryption_info.page0_has_crypt_data) |
| 6235 | ✗ | keyring_encryption_info = validate_output.keyring_encryption_info; | |
| 6236 | |||
| 6237 |
6/6✓ Branch 0 taken 18923 times.
✓ Branch 1 taken 34843 times.
✓ Branch 2 taken 18773 times.
✓ Branch 3 taken 150 times.
✓ Branch 4 taken 18232 times.
✓ Branch 5 taken 541 times.
|
53766 | if (validate && !old_space && !for_import) { |
| 6238 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18232 times.
|
18232 | if (df.server_version() > DD_SPACE_CURRENT_SRV_VERSION) { |
| 6239 | ✗ | ib::error(ER_IB_MSG_1272, ulong{DD_SPACE_CURRENT_SRV_VERSION}, | |
| 6240 | ✗ | ulonglong{df.server_version()}); | |
| 6241 | /* Server version is less than the tablespace server version. | ||
| 6242 | We don't support downgrade for 8.0 server, so report error */ | ||
| 6243 | ✗ | return DB_SERVER_VERSION_LOW; | |
| 6244 | } | ||
| 6245 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18232 times.
|
18232 | ut_ad(df.space_version() == DD_SPACE_CURRENT_SPACE_VERSION); |
| 6246 | } | ||
| 6247 | |||
| 6248 | /* We are done validating. If the tablespace is already open, | ||
| 6249 | return success. */ | ||
| 6250 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 53766 times.
|
53766 | if (space != nullptr) { |
| 6251 | ✗ | return DB_SUCCESS; | |
| 6252 | } | ||
| 6253 | |||
| 6254 | /* We pass UNINITIALIZED flags while we try to open DD tablespace. In that | ||
| 6255 | case, set the flags now based on what is read from disk.*/ | ||
| 6256 |
5/8✓ Branch 0 taken 133 times.
✓ Branch 1 taken 53633 times.
✓ Branch 2 taken 133 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 133 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 53766 times.
|
53766 | if (FSP_FLAGS_ARE_NOT_SET(flags) && fsp_is_dd_tablespace(space_id)) { |
| 6257 | ✗ | flags = df.flags(); | |
| 6258 | ✗ | is_encrypted = FSP_FLAGS_GET_ENCRYPTION(flags); | |
| 6259 | } | ||
| 6260 | |||
| 6261 | 53766 | fil_space_crypt_t *crypt_data = nullptr; | |
| 6262 | |||
| 6263 | { // Read keyring encryption data | ||
| 6264 | 53766 | bool close_df = false; | |
| 6265 | 54210 | auto guard = create_scope_guard([&close_df, &df]() { | |
| 6266 |
2/2✓ Branch 0 taken 444 times.
✓ Branch 1 taken 53322 times.
|
53766 | if (close_df) df.close(); |
| 6267 |
1/2✓ Branch 0 taken 53766 times.
✗ Branch 1 not taken.
|
53766 | }); |
| 6268 | |||
| 6269 |
5/6✓ Branch 0 taken 444 times.
✓ Branch 1 taken 53322 times.
✓ Branch 2 taken 444 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 444 times.
✓ Branch 5 taken 53322 times.
|
53766 | if (is_encrypted && !df.is_open()) { |
| 6270 | // df.validate_to_dd closes df | ||
| 6271 |
2/4✓ Branch 0 taken 444 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 444 times.
|
444 | if (df.open_read_only(strict) != DB_SUCCESS) { |
| 6272 | ✗ | ut_ad(!df.is_open()); | |
| 6273 | ✗ | return DB_CANNOT_OPEN_FILE; | |
| 6274 | } | ||
| 6275 | 444 | close_df = true; | |
| 6276 | } | ||
| 6277 | |||
| 6278 |
2/2✓ Branch 0 taken 34955 times.
✓ Branch 1 taken 18811 times.
|
53766 | const byte *first_page = df.is_open() ? df.get_first_page() : nullptr; |
| 6279 | 53766 | crypt_data = first_page | |
| 6280 |
4/6✓ Branch 0 taken 444 times.
✓ Branch 1 taken 53322 times.
✓ Branch 2 taken 444 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 444 times.
✗ Branch 5 not taken.
|
53766 | ? fil_space_read_crypt_data(page_size_t(flags), first_page) |
| 6281 | : nullptr; | ||
| 6282 | |||
| 6283 | 53766 | keyring_encryption_info.page0_has_crypt_data = crypt_data != nullptr; | |
| 6284 | 53766 | keyring_encryption_info.is_mk_to_keyring_rotation = | |
| 6285 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 53766 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
53766 | crypt_data != nullptr && crypt_data->encryption_rotation == |
| 6286 | Encryption_rotation::MASTER_KEY_TO_KEYRING; | ||
| 6287 |
1/2✓ Branch 0 taken 53766 times.
✗ Branch 1 not taken.
|
53766 | } |
| 6288 | |||
| 6289 |
1/2✓ Branch 0 taken 53766 times.
✗ Branch 1 not taken.
|
53766 | space = fil_space_create(space_name, space_id, flags, purpose, crypt_data); |
| 6290 | |||
| 6291 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 53764 times.
|
53766 | if (space == nullptr) { |
| 6292 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
2 | if (crypt_data != nullptr) fil_space_destroy_crypt_data(&crypt_data); |
| 6293 | 2 | return DB_ERROR; | |
| 6294 | } | ||
| 6295 | |||
| 6296 | /* We do not measure the size of the file, that is why | ||
| 6297 | we pass the 0 below */ | ||
| 6298 | |||
| 6299 | const fil_node_t *file = | ||
| 6300 |
1/2✓ Branch 0 taken 53764 times.
✗ Branch 1 not taken.
|
53764 | shard->create_node(df.filepath(), 0, space, false, |
| 6301 |
1/2✓ Branch 0 taken 53764 times.
✗ Branch 1 not taken.
|
53764 | IORequest::is_punch_hole_supported(), atomic_write); |
| 6302 | |||
| 6303 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 53764 times.
|
53764 | if (file == nullptr) { |
| 6304 | ✗ | return DB_ERROR; | |
| 6305 | } | ||
| 6306 | |||
| 6307 | /* Set encryption operation in progress */ | ||
| 6308 | 53764 | space->encryption_op_in_progress = df.m_encryption_op_in_progress; | |
| 6309 | |||
| 6310 | /* It's possible during Encryption processing, space flag for encryption | ||
| 6311 | has been updated in ibd file but server crashed before DD flags are | ||
| 6312 | updated. Thus, consider ibd setting for encryption. */ | ||
| 6313 |
2/2✓ Branch 0 taken 449 times.
✓ Branch 1 taken 53315 times.
|
53764 | if (FSP_FLAGS_GET_ENCRYPTION(df.flags())) { |
| 6314 | 449 | fsp_flags_set_encryption(space->flags); | |
| 6315 | } else { | ||
| 6316 | 53315 | fsp_flags_unset_encryption(space->flags); | |
| 6317 | } | ||
| 6318 | |||
| 6319 | /* For encryption tablespace, initialize encryption information.*/ | ||
| 6320 |
8/8✓ Branch 0 taken 53320 times.
✓ Branch 1 taken 444 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 53315 times.
✓ Branch 4 taken 409 times.
✓ Branch 5 taken 40 times.
✓ Branch 6 taken 409 times.
✓ Branch 7 taken 53355 times.
|
54173 | if ((is_encrypted || FSP_FLAGS_GET_ENCRYPTION(space->flags)) && !for_import && |
| 6321 |
1/2✓ Branch 0 taken 409 times.
✗ Branch 1 not taken.
|
409 | crypt_data == nullptr) { |
| 6322 | dberr_t err; | ||
| 6323 | 409 | byte *iv = df.m_encryption_iv; | |
| 6324 | 409 | byte *key = df.m_encryption_key; | |
| 6325 | |||
| 6326 |
1/2✓ Branch 0 taken 409 times.
✗ Branch 1 not taken.
|
409 | err = fil_set_encryption(space->id, Encryption::AES, key, iv); |
| 6327 | |||
| 6328 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 409 times.
|
409 | if (err != DB_SUCCESS) { |
| 6329 | ✗ | return DB_ERROR; | |
| 6330 | } | ||
| 6331 | |||
| 6332 | /* If tablespace is encrypted with default master key and server has already | ||
| 6333 | started, rotate it now. */ | ||
| 6334 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 409 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 409 times.
|
409 | if (df.m_encryption_master_key_id == Encryption::DEFAULT_MASTER_KEY_ID && |
| 6335 | /* There is no dependency on master thread but we are trying to check if | ||
| 6336 | server is in initial phase or not. */ | ||
| 6337 | ✗ | srv_master_thread_is_active()) { | |
| 6338 | /* Reencrypt tablespace key */ | ||
| 6339 | ✗ | std::vector<space_id_t> sid; | |
| 6340 | ✗ | sid.push_back(space->id); | |
| 6341 | ✗ | fil_encryption_reencrypt(sid); | |
| 6342 | } | ||
| 6343 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 53355 times.
|
53355 | } else if (crypt_data) { |
| 6344 | ✗ | dberr_t err = fil_set_encryption(space->id, Encryption::KEYRING, nullptr, | |
| 6345 | ✗ | crypt_data->iv); | |
| 6346 | ✗ | if (err != DB_SUCCESS) { | |
| 6347 | ✗ | return (DB_ERROR); | |
| 6348 | } | ||
| 6349 | } | ||
| 6350 | |||
| 6351 | 53764 | return DB_SUCCESS; | |
| 6352 | 53899 | } | |
| 6353 | |||
| 6354 | #else /* !UNIV_HOTBACKUP */ | ||
| 6355 | |||
| 6356 | /** Allocates a file name for an old version of a single-table tablespace. | ||
| 6357 | The string must be freed by caller with ut::free()! | ||
| 6358 | @param[in] name Original file name | ||
| 6359 | @return own: file name */ | ||
| 6360 | static char *meb_make_ibbackup_old_name(const char *name) { | ||
| 6361 | char *path; | ||
| 6362 | ulint len = strlen(name); | ||
| 6363 | static const char suffix[] = "_ibbackup_old_vers_"; | ||
| 6364 | |||
| 6365 | path = static_cast<char *>( | ||
| 6366 | ut::malloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, len + 15 + sizeof(suffix))); | ||
| 6367 | |||
| 6368 | memcpy(path, name, len); | ||
| 6369 | memcpy(path + len, suffix, sizeof(suffix) - 1); | ||
| 6370 | |||
| 6371 | meb_sprintf_timestamp_without_extra_chars(path + len + sizeof(suffix) - 1); | ||
| 6372 | |||
| 6373 | return path; | ||
| 6374 | } | ||
| 6375 | #endif /* UNIV_HOTBACKUP */ | ||
| 6376 | |||
| 6377 | /** Looks for a pre-existing fil_space_t with the given tablespace ID | ||
| 6378 | and, if found, returns the name and filepath in newly allocated buffers | ||
| 6379 | that the caller must free. | ||
| 6380 | @param[in] space_id The tablespace ID to search for. | ||
| 6381 | @param[out] name Name of the tablespace found. | ||
| 6382 | @param[out] filepath The filepath of the first datafile for the | ||
| 6383 | tablespace. | ||
| 6384 | @return true if tablespace is found, false if not. */ | ||
| 6385 | 47803 | bool fil_space_read_name_and_filepath(space_id_t space_id, char **name, | |
| 6386 | char **filepath) { | ||
| 6387 | 47803 | bool success = false; | |
| 6388 | |||
| 6389 | 47803 | *name = nullptr; | |
| 6390 | 47803 | *filepath = nullptr; | |
| 6391 | |||
| 6392 | 47803 | auto shard = fil_system->shard_by_id(space_id); | |
| 6393 | |||
| 6394 | 47803 | shard->mutex_acquire(); | |
| 6395 | |||
| 6396 | 47803 | fil_space_t *space = shard->get_space_by_id(space_id); | |
| 6397 | |||
| 6398 |
2/2✓ Branch 0 taken 173 times.
✓ Branch 1 taken 47630 times.
|
47803 | if (space != nullptr) { |
| 6399 | 173 | *name = mem_strdup(space->name); | |
| 6400 | |||
| 6401 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
|
173 | ut_a(space->files.size() == 1); |
| 6402 | 173 | *filepath = mem_strdup(space->files.front().name); | |
| 6403 | |||
| 6404 | 173 | success = true; | |
| 6405 | } | ||
| 6406 | |||
| 6407 | 47803 | shard->mutex_release(); | |
| 6408 | |||
| 6409 | 47803 | return success; | |
| 6410 | } | ||
| 6411 | |||
| 6412 | /** Convert a file name to a tablespace name. Strip the file name | ||
| 6413 | prefix and suffix, leaving only databasename/tablename. | ||
| 6414 | @param[in] filename directory/databasename/tablename.ibd | ||
| 6415 | @return database/tablename string, to be freed with ut::free() */ | ||
| 6416 | 4130 | char *fil_path_to_space_name(const char *filename) { | |
| 6417 |
1/2✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
|
4130 | std::string path{filename}; |
| 6418 | 4130 | auto pos = path.find_last_of(Fil_path::SEPARATOR); | |
| 6419 | |||
| 6420 |
3/6✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4130 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4130 times.
|
4130 | ut_a(pos != std::string::npos && !Fil_path::is_separator(path.back())); |
| 6421 | |||
| 6422 |
1/2✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
|
4130 | std::string db_name = path.substr(0, pos); |
| 6423 |
1/2✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
|
4130 | std::string space_name = path.substr(pos + 1, path.length()); |
| 6424 | |||
| 6425 | /* If it is a path such as a/b/c.ibd, ignore everything before 'b'. */ | ||
| 6426 | 4130 | pos = db_name.find_last_of(Fil_path::SEPARATOR); | |
| 6427 | |||
| 6428 |
1/2✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
|
4130 | if (pos != std::string::npos) { |
| 6429 |
1/2✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
|
4130 | db_name = db_name.substr(pos + 1); |
| 6430 | } | ||
| 6431 | |||
| 6432 | char *name; | ||
| 6433 | |||
| 6434 |
2/4✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4130 times.
✗ Branch 3 not taken.
|
4130 | if (Fil_path::has_suffix(IBD, space_name)) { |
| 6435 | /* fil_space_t::name always uses '/' . */ | ||
| 6436 | |||
| 6437 |
1/2✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
|
4130 | path = db_name; |
| 6438 |
1/2✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
|
4130 | path.push_back('/'); |
| 6439 | |||
| 6440 | /* Strip the ".ibd" suffix. */ | ||
| 6441 |
2/4✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4130 times.
✗ Branch 3 not taken.
|
4130 | path.append(space_name.substr(0, space_name.length() - 4)); |
| 6442 | |||
| 6443 |
1/2✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
|
4130 | name = mem_strdupl(path.c_str(), path.length()); |
| 6444 | |||
| 6445 | } else { | ||
| 6446 | /* Must have an "undo" prefix. */ | ||
| 6447 | ✗ | ut_ad(space_name.find("undo") == 0); | |
| 6448 | |||
| 6449 | ✗ | name = mem_strdupl(space_name.c_str(), space_name.length()); | |
| 6450 | } | ||
| 6451 | |||
| 6452 | 4130 | return name; | |
| 6453 | 4130 | } | |
| 6454 | |||
| 6455 | /** Open an ibd tablespace and add it to the InnoDB data structures. | ||
| 6456 | This is similar to fil_ibd_open() except that it is used while processing | ||
| 6457 | the redo and DDL log, so the data dictionary is not available and very little | ||
| 6458 | validation is done. The tablespace name is extracted from the | ||
| 6459 | dbname/tablename.ibd portion of the filename, which assumes that the file | ||
| 6460 | is a file-per-table tablespace. Any name will do for now. General | ||
| 6461 | tablespace names will be read from the dictionary after it has been | ||
| 6462 | recovered. The tablespace flags are read at this time from the first page | ||
| 6463 | of the file in validate_for_recovery(). | ||
| 6464 | @param[in] space_id tablespace ID | ||
| 6465 | @param[in] path path/to/databasename/tablename.ibd | ||
| 6466 | @param[out] space the tablespace, or nullptr on error | ||
| 6467 | @return status of the operation */ | ||
| 6468 | 16121 | fil_load_status Fil_shard::ibd_open_for_recovery(space_id_t space_id, | |
| 6469 | const std::string &path, | ||
| 6470 | fil_space_t *&space) { | ||
| 6471 | /* If the a space is already in the file system cache with this | ||
| 6472 | space ID, then there is nothing to do. */ | ||
| 6473 | |||
| 6474 |
1/2✓ Branch 0 taken 16121 times.
✗ Branch 1 not taken.
|
16121 | mutex_acquire(); |
| 6475 | |||
| 6476 |
1/2✓ Branch 0 taken 16121 times.
✗ Branch 1 not taken.
|
16121 | space = get_space_by_id(space_id); |
| 6477 | |||
| 6478 |
1/2✓ Branch 0 taken 16121 times.
✗ Branch 1 not taken.
|
16121 | mutex_release(); |
| 6479 | |||
| 6480 | 16121 | const char *filename = path.c_str(); | |
| 6481 | |||
| 6482 |
2/2✓ Branch 0 taken 6698 times.
✓ Branch 1 taken 9423 times.
|
16121 | if (space != nullptr) { |
| 6483 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6698 times.
|
6698 | ut_a(space->files.size() == 1); |
| 6484 | |||
| 6485 | 6698 | const auto &file = space->files.front(); | |
| 6486 | |||
| 6487 | /* Compare the real paths. */ | ||
| 6488 |
4/8✓ Branch 0 taken 6698 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6698 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6698 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6698 times.
✗ Branch 7 not taken.
|
6698 | if (Fil_path::is_same_as(filename, file.name)) { |
| 6489 | 6698 | return FIL_LOAD_OK; | |
| 6490 | } | ||
| 6491 | |||
| 6492 | #ifdef UNIV_HOTBACKUP | ||
| 6493 | ib::trace_2() << "Ignoring data file '" << filename << "' with space ID " | ||
| 6494 | << space->id << ". Another data file called '" << file.name | ||
| 6495 | << "' exists with the same space ID"; | ||
| 6496 | #else /* UNIV_HOTBACKUP */ | ||
| 6497 | ✗ | ib::info(ER_IB_MSG_307, filename, ulong{space->id}, file.name); | |
| 6498 | #endif /* UNIV_HOTBACKUP */ | ||
| 6499 | |||
| 6500 | ✗ | space = nullptr; | |
| 6501 | |||
| 6502 | ✗ | return FIL_LOAD_ID_CHANGED; | |
| 6503 | } | ||
| 6504 | |||
| 6505 | 9423 | Datafile df; | |
| 6506 | |||
| 6507 |
1/2✓ Branch 0 taken 9423 times.
✗ Branch 1 not taken.
|
9423 | df.set_filepath(filename); |
| 6508 | |||
| 6509 |
2/4✓ Branch 0 taken 9423 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9423 times.
|
9423 | if (df.open_read_only(false) != DB_SUCCESS) { |
| 6510 | ✗ | return FIL_LOAD_NOT_FOUND; | |
| 6511 | } | ||
| 6512 | |||
| 6513 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9423 times.
|
9423 | ut_ad(df.is_open()); |
| 6514 | |||
| 6515 | /* Get and test the file size. */ | ||
| 6516 |
2/4✓ Branch 0 taken 9423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9423 times.
✗ Branch 3 not taken.
|
9423 | os_offset_t size = os_file_get_size(df.handle()); |
| 6517 | |||
| 6518 | /* Read and validate the first page of the tablespace. Assign a tablespace | ||
| 6519 | name based on the tablespace type. This will close the file, but will leave | ||
| 6520 | the flags and names to be queried. */ | ||
| 6521 |
1/2✓ Branch 0 taken 9423 times.
✗ Branch 1 not taken.
|
9423 | dberr_t err = df.validate_for_recovery(space_id).error; |
| 6522 | |||
| 6523 |
4/8✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9419 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 9423 times.
|
9423 | ut_a(err == DB_SUCCESS || err == DB_INVALID_ENCRYPTION_META || |
| 6524 | err == DB_CORRUPTION); | ||
| 6525 | |||
| 6526 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9423 times.
|
9423 | if (err == DB_CORRUPTION) { |
| 6527 | ✗ | return FIL_LOAD_DBWLR_CORRUPTION; | |
| 6528 | } | ||
| 6529 | |||
| 6530 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9419 times.
|
9423 | if (err == DB_INVALID_ENCRYPTION_META) { |
| 6531 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | bool success = fil_system->erase_path(space_id); |
| 6532 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | ut_a(success); |
| 6533 | 4 | return FIL_LOAD_NOT_FOUND; | |
| 6534 | } | ||
| 6535 | |||
| 6536 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
|
9419 | ut_a(df.space_id() == space_id); |
| 6537 | |||
| 6538 | /* Every .ibd file is created >= 4 pages in size. | ||
| 6539 | Smaller files cannot be OK. */ | ||
| 6540 | os_offset_t minimum_size; | ||
| 6541 | |||
| 6542 | /* Every .ibd file is created >= FIL_IBD_FILE_INITIAL_SIZE | ||
| 6543 | pages in size. Smaller files cannot be OK. */ | ||
| 6544 | { | ||
| 6545 |
1/2✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
|
9419 | const page_size_t page_size(df.flags()); |
| 6546 | |||
| 6547 |
1/2✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
|
9419 | minimum_size = FIL_IBD_FILE_INITIAL_SIZE * page_size.physical(); |
| 6548 | } | ||
| 6549 | |||
| 6550 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
|
9419 | if (size == static_cast<os_offset_t>(-1)) { |
| 6551 | /* The following call prints an error message */ | ||
| 6552 | ✗ | os_file_get_last_error(true); | |
| 6553 | |||
| 6554 | ✗ | ib::error(ER_IB_MSG_308) << "Could not measure the size of" | |
| 6555 | ✗ | " single-table tablespace file '" | |
| 6556 | ✗ | << df.filepath() << "'"; | |
| 6557 | |||
| 6558 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
|
9419 | } else if (size < minimum_size) { |
| 6559 | #ifndef UNIV_HOTBACKUP | ||
| 6560 | ✗ | ib::error(ER_IB_MSG_309) | |
| 6561 | ✗ | << "The size of tablespace file '" << df.filepath() << "' is only " | |
| 6562 | ✗ | << size << ", should be at least " << minimum_size << "!"; | |
| 6563 | #else | ||
| 6564 | /* In MEB, we work around this error. */ | ||
| 6565 | df.set_space_id(SPACE_UNKNOWN); | ||
| 6566 | df.set_flags(0); | ||
| 6567 | #endif /* !UNIV_HOTBACKUP */ | ||
| 6568 | } | ||
| 6569 | |||
| 6570 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
|
9419 | ut_ad(space == nullptr); |
| 6571 | |||
| 6572 | #ifdef UNIV_HOTBACKUP | ||
| 6573 | if (df.space_id() == SPACE_UNKNOWN || df.space_id() == 0) { | ||
| 6574 | char *new_path; | ||
| 6575 | |||
| 6576 | ib::info(ER_IB_MSG_310) | ||
| 6577 | << "Renaming tablespace file '" << df.filepath() << "' with space ID " | ||
| 6578 | << df.space_id() << " to " << df.name() | ||
| 6579 | << "_ibbackup_old_vers_<timestamp>" | ||
| 6580 | " because its size " | ||
| 6581 | << df.size() | ||
| 6582 | << " is too small" | ||
| 6583 | " (< 4 pages 16 kB each), or the space id in the" | ||
| 6584 | " file header is not sensible. This can happen in" | ||
| 6585 | " an mysqlbackup run, and is not dangerous."; | ||
| 6586 | df.close(); | ||
| 6587 | |||
| 6588 | new_path = meb_make_ibbackup_old_name(df.filepath()); | ||
| 6589 | |||
| 6590 | bool success = | ||
| 6591 | os_file_rename(innodb_data_file_key, df.filepath(), new_path); | ||
| 6592 | |||
| 6593 | ut_a(success); | ||
| 6594 | |||
| 6595 | ut::free(new_path); | ||
| 6596 | |||
| 6597 | return FIL_LOAD_ID_CHANGED; | ||
| 6598 | } | ||
| 6599 | |||
| 6600 | /* A backup may contain the same space several times, if the space got | ||
| 6601 | renamed at a sensitive time. Since it is enough to have one version of | ||
| 6602 | the space, we rename the file if a space with the same space id | ||
| 6603 | already exists in the tablespace memory cache. We rather rename the | ||
| 6604 | file than delete it, because if there is a bug, we do not want to | ||
| 6605 | destroy valuable data. */ | ||
| 6606 | |||
| 6607 | mutex_acquire(); | ||
| 6608 | |||
| 6609 | space = get_space_by_id(space_id); | ||
| 6610 | |||
| 6611 | mutex_release(); | ||
| 6612 | |||
| 6613 | if (space != nullptr) { | ||
| 6614 | ib::info(ER_IB_MSG_311) | ||
| 6615 | << "Renaming data file '" << df.filepath() << "' with space ID " | ||
| 6616 | << space_id << " to " << df.name() | ||
| 6617 | << "_ibbackup_old_vers_<timestamp> because space " << space->name | ||
| 6618 | << " with the same id was scanned" | ||
| 6619 | " earlier. This can happen if you have renamed tables" | ||
| 6620 | " during an mysqlbackup run."; | ||
| 6621 | |||
| 6622 | df.close(); | ||
| 6623 | |||
| 6624 | char *new_path = meb_make_ibbackup_old_name(df.filepath()); | ||
| 6625 | |||
| 6626 | bool success = | ||
| 6627 | os_file_rename(innodb_data_file_key, df.filepath(), new_path); | ||
| 6628 | |||
| 6629 | ut_a(success); | ||
| 6630 | |||
| 6631 | ut::free(new_path); | ||
| 6632 | return FIL_LOAD_OK; | ||
| 6633 | } | ||
| 6634 | #endif /* UNIV_HOTBACKUP */ | ||
| 6635 |
1/2✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
|
9419 | std::string tablespace_name(df.name()); |
| 6636 | |||
| 6637 | /* During the apply-log operation, MEB already has translated the | ||
| 6638 | file name, so file name to space name conversion is not required. */ | ||
| 6639 | #ifndef UNIV_HOTBACKUP | ||
| 6640 |
1/2✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
|
9419 | dict_name::convert_to_space(tablespace_name); |
| 6641 | #endif /* !UNIV_HOTBACKUP */ | ||
| 6642 | |||
| 6643 | 9419 | const byte *first_page = df.get_first_page(); | |
| 6644 | fil_space_crypt_t *crypt_data = | ||
| 6645 | first_page | ||
| 6646 |
3/6✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9419 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9419 times.
✗ Branch 5 not taken.
|
9419 | ? fil_space_read_crypt_data(page_size_t(df.flags()), first_page) |
| 6647 | 9419 | : nullptr; | |
| 6648 | |||
| 6649 |
1/2✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
|
9419 | fil_system->mutex_acquire_all(); |
| 6650 | |||
| 6651 |
1/2✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
|
9419 | space = space_create(tablespace_name.c_str(), space_id, df.flags(), |
| 6652 | FIL_TYPE_TABLESPACE, crypt_data); | ||
| 6653 | |||
| 6654 |
1/2✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
|
9419 | fil_system->mutex_release_all(); |
| 6655 | |||
| 6656 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
|
9419 | if (space == nullptr) { |
| 6657 | ✗ | return FIL_LOAD_INVALID; | |
| 6658 | } | ||
| 6659 | |||
| 6660 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
|
9419 | ut_ad(space->id == df.space_id()); |
| 6661 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
|
9419 | ut_ad(space->id == space_id); |
| 6662 | |||
| 6663 | /* We do not use the size information we have about the file, because | ||
| 6664 | the rounding formula for extents and pages is somewhat complex; we | ||
| 6665 | let create_node() do that task. */ | ||
| 6666 | |||
| 6667 | const fil_node_t *file; | ||
| 6668 | |||
| 6669 |
1/2✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
|
9419 | file = create_node(df.filepath(), 0, space, false, true, false); |
| 6670 | |||
| 6671 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
|
9419 | ut_a(file != nullptr); |
| 6672 | |||
| 6673 | /* For encryption tablespace, initial encryption information. */ | ||
| 6674 |
4/4✓ Branch 0 taken 212 times.
✓ Branch 1 taken 9207 times.
✓ Branch 2 taken 198 times.
✓ Branch 3 taken 9221 times.
|
9631 | if (FSP_FLAGS_GET_ENCRYPTION(space->flags) && |
| 6675 |
2/2✓ Branch 0 taken 198 times.
✓ Branch 1 taken 14 times.
|
212 | df.m_encryption_key != nullptr) { |
| 6676 |
1/2✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
|
198 | dberr_t err = fil_set_encryption(space->id, Encryption::AES, |
| 6677 | df.m_encryption_key, df.m_encryption_iv); | ||
| 6678 | |||
| 6679 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
|
198 | if (err != DB_SUCCESS) { |
| 6680 | ✗ | ib::error(ER_IB_MSG_312, space->name); | |
| 6681 | } | ||
| 6682 | } | ||
| 6683 | |||
| 6684 | /* Set encryption operation in progress */ | ||
| 6685 | 9419 | space->encryption_op_in_progress = df.m_encryption_op_in_progress; | |
| 6686 |
1/2✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
|
9419 | space->m_header_page_flush_lsn = df.get_flush_lsn(); |
| 6687 | |||
| 6688 | 9419 | return FIL_LOAD_OK; | |
| 6689 | 9423 | } | |
| 6690 | |||
| 6691 | /** Open an ibd tablespace and add it to the InnoDB data structures. | ||
| 6692 | This is similar to fil_ibd_open() except that it is used while processing | ||
| 6693 | the redo log, so the data dictionary is not available and very little | ||
| 6694 | validation is done. The tablespace name is extracted from the | ||
| 6695 | dbname/tablename.ibd portion of the filename, which assumes that the file | ||
| 6696 | is a file-per-table tablespace. Any name will do for now. General | ||
| 6697 | tablespace names will be read from the dictionary after it has been | ||
| 6698 | recovered. The tablespace flags are read at this time from the first page | ||
| 6699 | of the file in validate_for_recovery(). | ||
| 6700 | @param[in] space_id tablespace ID | ||
| 6701 | @param[in] path path/to/databasename/tablename.ibd | ||
| 6702 | @param[out] space the tablespace, or nullptr on error | ||
| 6703 | @return status of the operation */ | ||
| 6704 | 16131 | fil_load_status Fil_system::ibd_open_for_recovery(space_id_t space_id, | |
| 6705 | const std::string &path, | ||
| 6706 | fil_space_t *&space) { | ||
| 6707 | /* System tablespace open should never come here. It should be | ||
| 6708 | opened explicitly using the config path. */ | ||
| 6709 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16131 times.
|
16131 | ut_a(space_id != TRX_SYS_SPACE); |
| 6710 | |||
| 6711 | #ifndef UNIV_HOTBACKUP | ||
| 6712 | /* Do not attempt to open or load for recovery any undo tablespace that | ||
| 6713 | is currently being truncated. */ | ||
| 6714 |
4/4✓ Branch 0 taken 3697 times.
✓ Branch 1 taken 12434 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 16121 times.
|
19828 | if (fsp_is_undo_tablespace(space_id) && |
| 6715 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 3687 times.
|
3697 | undo::is_active_truncate_log_present(undo::id2num(space_id))) { |
| 6716 | 10 | return FIL_LOAD_NOT_FOUND; | |
| 6717 | } | ||
| 6718 | #endif /* !UNIV_HOTBACKUP */ | ||
| 6719 | |||
| 6720 | 16121 | auto shard = shard_by_id(space_id); | |
| 6721 | |||
| 6722 | 16121 | return shard->ibd_open_for_recovery(space_id, path, space); | |
| 6723 | } | ||
| 6724 | |||
| 6725 | #ifndef UNIV_HOTBACKUP | ||
| 6726 | |||
| 6727 | /** Report that a tablespace for a table was not found. | ||
| 6728 | @param[in] name Table name | ||
| 6729 | @param[in] space_id Table's space ID */ | ||
| 6730 | ✗ | static void fil_report_missing_tablespace(const char *name, | |
| 6731 | space_id_t space_id) { | ||
| 6732 | ✗ | ib::error(ER_IB_MSG_313) | |
| 6733 | ✗ | << "Table " << name << " in the InnoDB data dictionary has tablespace id " | |
| 6734 | ✗ | << space_id << ", but a tablespace with that id or name does not exist." | |
| 6735 | ✗ | << " Have you deleted or moved .ibd files?"; | |
| 6736 | } | ||
| 6737 | |||
| 6738 | 842077 | bool Fil_shard::adjust_space_name(fil_space_t *space, | |
| 6739 | const char *dd_space_name) { | ||
| 6740 |
2/2✓ Branch 0 taken 841091 times.
✓ Branch 1 taken 986 times.
|
842077 | if (!strcmp(space->name, dd_space_name)) { |
| 6741 | 841091 | return true; | |
| 6742 | } | ||
| 6743 | |||
| 6744 | bool replace_general = | ||
| 6745 |
2/2✓ Branch 0 taken 157 times.
✓ Branch 1 taken 829 times.
|
1143 | FSP_FLAGS_GET_SHARED(space->flags) && |
| 6746 |
1/2✓ Branch 0 taken 157 times.
✗ Branch 1 not taken.
|
157 | 0 == strncmp(space->name, general_space_name, strlen(general_space_name)); |
| 6747 | bool replace_undo = | ||
| 6748 |
2/2✓ Branch 0 taken 263 times.
✓ Branch 1 taken 723 times.
|
1249 | fsp_is_undo_tablespace(space->id) && |
| 6749 |
1/2✓ Branch 0 taken 263 times.
✗ Branch 1 not taken.
|
263 | 0 == strncmp(space->name, undo_space_name, strlen(undo_space_name)); |
| 6750 | |||
| 6751 | /* Update the auto-generated fil_space_t::name */ | ||
| 6752 |
4/4✓ Branch 0 taken 829 times.
✓ Branch 1 taken 157 times.
✓ Branch 2 taken 263 times.
✓ Branch 3 taken 566 times.
|
986 | if (replace_general || replace_undo) { |
| 6753 | 420 | char *old_space_name = space->name; | |
| 6754 | 420 | char *new_space_name = mem_strdup(dd_space_name); | |
| 6755 | |||
| 6756 | 420 | update_space_name_map(space, new_space_name); | |
| 6757 | |||
| 6758 | 420 | space->name = new_space_name; | |
| 6759 | |||
| 6760 | 420 | ut::free(old_space_name); | |
| 6761 | } | ||
| 6762 | |||
| 6763 | /* Update the undo::Tablespace::name. Since the fil_shard mutex is held by | ||
| 6764 | the caller, it would be a sync order violation to get undo::spaces->s_lock. | ||
| 6765 | It is OK to skip this s_lock since this occurs during boot_tablespaces() | ||
| 6766 | which is still single threaded. */ | ||
| 6767 |
2/2✓ Branch 0 taken 263 times.
✓ Branch 1 taken 723 times.
|
986 | if (replace_undo) { |
| 6768 | 263 | space_id_t space_num = undo::id2num(space->id); | |
| 6769 | 263 | undo::Tablespace *undo_space = undo::spaces->find(space_num); | |
| 6770 | 263 | undo_space->set_space_name(dd_space_name); | |
| 6771 | } | ||
| 6772 | |||
| 6773 |
4/4✓ Branch 0 taken 829 times.
✓ Branch 1 taken 157 times.
✓ Branch 2 taken 263 times.
✓ Branch 3 taken 566 times.
|
986 | return (replace_general || replace_undo); |
| 6774 | } | ||
| 6775 | |||
| 6776 | 1074228 | bool Fil_shard::space_check_exists(space_id_t space_id, const char *name, | |
| 6777 | bool print_err, bool adjust_space) { | ||
| 6778 | 1074228 | fil_space_t *fnamespace = nullptr; | |
| 6779 | |||
| 6780 | 1074228 | mutex_acquire(); | |
| 6781 | |||
| 6782 | /* Look if there is a space with the same id */ | ||
| 6783 | 1074228 | fil_space_t *space = get_space_by_id(space_id); | |
| 6784 | |||
| 6785 | /* name is nullptr when replaying a DELETE ddl log. */ | ||
| 6786 |
2/2✓ Branch 0 taken 186214 times.
✓ Branch 1 taken 888014 times.
|
1074228 | if (name == nullptr) { |
| 6787 | 186214 | mutex_release(); | |
| 6788 | 186214 | return (space != nullptr); | |
| 6789 | } | ||
| 6790 | |||
| 6791 |
2/2✓ Branch 0 taken 842077 times.
✓ Branch 1 taken 45937 times.
|
888014 | if (space != nullptr) { |
| 6792 | /* No need to check a general tablespace name if the DD | ||
| 6793 | is not yet available. */ | ||
| 6794 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 842077 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 842077 times.
|
842077 | if (!srv_sys_tablespaces_open && FSP_FLAGS_GET_SHARED(space->flags)) { |
| 6795 | ✗ | mutex_release(); | |
| 6796 | ✗ | return true; | |
| 6797 | } | ||
| 6798 | |||
| 6799 | /* Sometimes the name has been auto-generated when the | ||
| 6800 | datafile is discovered and needs to be adjusted to that | ||
| 6801 | of the DD. This happens for general and undo tablespaces. */ | ||
| 6802 |
4/6✓ Branch 0 taken 842077 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 842077 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 841511 times.
✓ Branch 5 taken 566 times.
|
1684154 | if (srv_sys_tablespaces_open && adjust_space && |
| 6803 |
2/2✓ Branch 0 taken 841511 times.
✓ Branch 1 taken 566 times.
|
842077 | adjust_space_name(space, name)) { |
| 6804 | 841511 | mutex_release(); | |
| 6805 | 841511 | return true; | |
| 6806 | } | ||
| 6807 | |||
| 6808 | /* If this space has the expected name, use it. */ | ||
| 6809 | 566 | fnamespace = get_space_by_name(name); | |
| 6810 | |||
| 6811 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 566 times.
|
566 | if (space == fnamespace) { |
| 6812 | /* Found */ | ||
| 6813 | ✗ | mutex_release(); | |
| 6814 | ✗ | return true; | |
| 6815 | } | ||
| 6816 | } | ||
| 6817 | |||
| 6818 | /* Info from "fnamespace" comes from the ibd file itself, it can | ||
| 6819 | be different from data obtained from System tables since file | ||
| 6820 | operations are not transactional. If adjust_space is set, and the | ||
| 6821 | mismatching space are between a user table and its temp table, we | ||
| 6822 | shall adjust the ibd file name according to system table info */ | ||
| 6823 |
2/2✓ Branch 0 taken 566 times.
✓ Branch 1 taken 45874 times.
|
46440 | if (adjust_space && space != nullptr && |
| 6824 |
6/6✓ Branch 0 taken 46440 times.
✓ Branch 1 taken 63 times.
✓ Branch 2 taken 347 times.
✓ Branch 3 taken 219 times.
✓ Branch 4 taken 347 times.
✓ Branch 5 taken 46156 times.
|
93290 | row_is_mysql_tmp_table_name(space->name) && |
| 6825 |
1/2✓ Branch 0 taken 347 times.
✗ Branch 1 not taken.
|
347 | !row_is_mysql_tmp_table_name(name)) { |
| 6826 | /* Atomic DDL's "ddl_log" will adjust the tablespace name. */ | ||
| 6827 | 347 | mutex_release(); | |
| 6828 | |||
| 6829 | 347 | return true; | |
| 6830 | |||
| 6831 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46156 times.
|
46156 | } else if (!print_err) { |
| 6832 | ; | ||
| 6833 | |||
| 6834 | ✗ | } else if (space == nullptr) { | |
| 6835 | ✗ | if (fnamespace == nullptr) { | |
| 6836 | ✗ | if (print_err) { | |
| 6837 | ✗ | fil_report_missing_tablespace(name, space_id); | |
| 6838 | } | ||
| 6839 | |||
| 6840 | } else { | ||
| 6841 | ✗ | ib::error(ER_IB_MSG_314) | |
| 6842 | ✗ | << "Table " << name << " in InnoDB data dictionary has tablespace id " | |
| 6843 | ✗ | << space_id << ", but a tablespace with that id does not exist." | |
| 6844 | ✗ | << " But there is a tablespace of name " << fnamespace->name | |
| 6845 | ✗ | << " and id " << fnamespace->id | |
| 6846 | ✗ | << ". Have you deleted or moved .ibd files?"; | |
| 6847 | } | ||
| 6848 | |||
| 6849 | ✗ | ib::warn(ER_IB_MSG_315) << TROUBLESHOOT_DATADICT_MSG; | |
| 6850 | |||
| 6851 | ✗ | } else if (0 != strcmp(space->name, name)) { | |
| 6852 | ✗ | ib::error(ER_IB_MSG_316) | |
| 6853 | ✗ | << "Table " << name << " in InnoDB data dictionary" | |
| 6854 | ✗ | << " has tablespace id " << space_id | |
| 6855 | ✗ | << ", but the tablespace with that id has name " << space->name | |
| 6856 | ✗ | << ". Have you deleted or moved .ibd files?"; | |
| 6857 | |||
| 6858 | ✗ | if (fnamespace != nullptr) { | |
| 6859 | ✗ | ib::error(ER_IB_MSG_317) | |
| 6860 | ✗ | << "There is a tablespace with the name " << fnamespace->name | |
| 6861 | ✗ | << ", but its id is " << fnamespace->id << "."; | |
| 6862 | } | ||
| 6863 | |||
| 6864 | ✗ | ib::warn(ER_IB_MSG_318) << TROUBLESHOOT_DATADICT_MSG; | |
| 6865 | } | ||
| 6866 | |||
| 6867 | 46156 | mutex_release(); | |
| 6868 | |||
| 6869 | 46156 | return false; | |
| 6870 | } | ||
| 6871 | |||
| 6872 | 1074228 | bool fil_space_exists_in_mem(space_id_t space_id, const char *name, | |
| 6873 | bool print_err, bool adjust_space) { | ||
| 6874 | 1074228 | auto shard = fil_system->shard_by_id(space_id); | |
| 6875 | |||
| 6876 | 1074228 | return shard->space_check_exists(space_id, name, print_err, adjust_space); | |
| 6877 | } | ||
| 6878 | #endif /* !UNIV_HOTBACKUP */ | ||
| 6879 | |||
| 6880 | /** Returns the space ID based on the tablespace name. | ||
| 6881 | The tablespace must be found in the tablespace memory cache. | ||
| 6882 | This call is made from external to this module, so the mutex is not owned. | ||
| 6883 | @param[in] name Tablespace name | ||
| 6884 | @return space ID if tablespace found, SPACE_UNKNOWN if space not. */ | ||
| 6885 | 154433 | space_id_t fil_space_get_id_by_name(const char *name) { | |
| 6886 | 154433 | auto space = fil_system->get_space_by_name(name); | |
| 6887 | |||
| 6888 |
2/2✓ Branch 0 taken 153117 times.
✓ Branch 1 taken 1316 times.
|
154433 | return (space == nullptr) ? SPACE_UNKNOWN : space->id; |
| 6889 | } | ||
| 6890 | |||
| 6891 | /** Fill the pages with NULs | ||
| 6892 | @param[in] file Tablespace file | ||
| 6893 | @param[in] page_size physical page size | ||
| 6894 | @param[in] start Offset from the start of the file in bytes | ||
| 6895 | @param[in] len Length in bytes | ||
| 6896 | @return DB_SUCCESS or error code */ | ||
| 6897 | 183568 | static dberr_t fil_write_zeros(const fil_node_t *file, ulint page_size, | |
| 6898 | os_offset_t start, os_offset_t len) { | ||
| 6899 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 183568 times.
|
183568 | ut_a(len > 0); |
| 6900 | |||
| 6901 | /* Extend at most 1M at a time */ | ||
| 6902 | 183568 | os_offset_t n_bytes = std::min(static_cast<os_offset_t>(1024 * 1024), len); | |
| 6903 | |||
| 6904 | 183568 | byte *buf = reinterpret_cast<byte *>(ut::aligned_zalloc(n_bytes, page_size)); | |
| 6905 | |||
| 6906 | 183568 | os_offset_t offset = start; | |
| 6907 | 183568 | dberr_t err = DB_SUCCESS; | |
| 6908 | 183568 | const os_offset_t end = start + len; | |
| 6909 |
1/2✓ Branch 0 taken 183568 times.
✗ Branch 1 not taken.
|
183568 | IORequest request(IORequest::WRITE); |
| 6910 | |||
| 6911 |
2/2✓ Branch 0 taken 192794 times.
✓ Branch 1 taken 183568 times.
|
376362 | while (offset < end) { |
| 6912 | err = | ||
| 6913 |
1/2✓ Branch 0 taken 192794 times.
✗ Branch 1 not taken.
|
192794 | os_file_write(request, file->name, file->handle, buf, offset, n_bytes); |
| 6914 | |||
| 6915 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 192794 times.
|
192794 | if (err != DB_SUCCESS) { |
| 6916 | ✗ | break; | |
| 6917 | } | ||
| 6918 | |||
| 6919 | 192794 | offset += n_bytes; | |
| 6920 | |||
| 6921 | 192794 | n_bytes = std::min(n_bytes, end - offset); | |
| 6922 | |||
| 6923 |
2/6✓ Branch 0 taken 192794 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 192794 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
192794 | DBUG_EXECUTE_IF("ib_crash_during_tablespace_extension", DBUG_SUICIDE();); |
| 6924 | } | ||
| 6925 | |||
| 6926 | 183568 | ut::aligned_free(buf); | |
| 6927 | |||
| 6928 | 183568 | return err; | |
| 6929 | 183568 | } | |
| 6930 | |||
| 6931 | /** Try to extend a tablespace if it is smaller than the specified size. | ||
| 6932 | @param[in,out] space tablespace | ||
| 6933 | @param[in] size desired size in pages | ||
| 6934 | @return whether the tablespace is at least as big as requested */ | ||
| 6935 | 273924 | bool Fil_shard::space_extend(fil_space_t *space, page_no_t size) { | |
| 6936 | /* In read-only mode we allow write to shared temporary tablespace | ||
| 6937 | as intrinsic table created by Optimizer reside in this tablespace. */ | ||
| 6938 |
5/8✓ Branch 0 taken 39 times.
✓ Branch 1 taken 273885 times.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 273924 times.
|
273924 | ut_ad(!srv_read_only_mode || fsp_is_system_temporary(space->id)); |
| 6939 | |||
| 6940 | #ifndef UNIV_HOTBACKUP | ||
| 6941 |
2/6✓ Branch 0 taken 273924 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 273924 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
273924 | DBUG_EXECUTE_IF("fil_space_print_xdes_pages", |
| 6942 | space->print_xdes_pages("xdes_pages.log");); | ||
| 6943 | #endif /* !UNIV_HOTBACKUP */ | ||
| 6944 | |||
| 6945 | fil_node_t *file; | ||
| 6946 | 273924 | bool success = true; | |
| 6947 | |||
| 6948 | #ifdef UNIV_HOTBACKUP | ||
| 6949 | page_no_t prev_size = 0; | ||
| 6950 | #endif /* UNIV_HOTBACKUP */ | ||
| 6951 | |||
| 6952 | for (;;) { | ||
| 6953 |
1/2✓ Branch 0 taken 273924 times.
✗ Branch 1 not taken.
|
273924 | mutex_acquire(); |
| 6954 |
1/2✓ Branch 0 taken 273924 times.
✗ Branch 1 not taken.
|
273924 | space = get_space_by_id(space->id); |
| 6955 | |||
| 6956 | /* Note:If the file is being opened for the first time then | ||
| 6957 | we don't have the file physical size. There is no guarantee | ||
| 6958 | that the file has been opened at this stage. */ | ||
| 6959 | |||
| 6960 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 273909 times.
|
273924 | if (size < space->size) { |
| 6961 | /* Space already big enough */ | ||
| 6962 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | mutex_release(); |
| 6963 | |||
| 6964 | 15 | return true; | |
| 6965 | } | ||
| 6966 | |||
| 6967 | 273909 | file = &space->files.back(); | |
| 6968 | |||
| 6969 |
1/2✓ Branch 0 taken 273909 times.
✗ Branch 1 not taken.
|
273909 | if (!file->is_being_extended) { |
| 6970 | /* Mark this file as undergoing extension. This flag | ||
| 6971 | is used to synchronize threads to execute space extension in order. */ | ||
| 6972 | |||
| 6973 | 273909 | file->is_being_extended = true; | |
| 6974 | |||
| 6975 | 273909 | break; | |
| 6976 | } | ||
| 6977 | |||
| 6978 | /* Another thread is currently using the file. Wait | ||
| 6979 | for it to finish. It'd have been better to use an event | ||
| 6980 | driven mechanism but the entire module is peppered with | ||
| 6981 | polling code. */ | ||
| 6982 | |||
| 6983 | ✗ | mutex_release(); | |
| 6984 | |||
| 6985 | ✗ | if (!tbsp_extend_and_initialize) { | |
| 6986 | ✗ | std::this_thread::sleep_for(std::chrono::microseconds(20)); | |
| 6987 | } else { | ||
| 6988 | ✗ | std::this_thread::sleep_for(std::chrono::milliseconds(100)); | |
| 6989 | } | ||
| 6990 | } | ||
| 6991 | |||
| 6992 |
2/4✓ Branch 0 taken 273909 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 273909 times.
|
273909 | if (!prepare_file_for_io(file)) { |
| 6993 | /* The tablespace data file, such as .ibd file, is missing */ | ||
| 6994 | ✗ | ut_a(file->is_being_extended); | |
| 6995 | ✗ | file->is_being_extended = false; | |
| 6996 | |||
| 6997 | ✗ | mutex_release(); | |
| 6998 | |||
| 6999 | ✗ | return false; | |
| 7000 | } | ||
| 7001 | |||
| 7002 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 273909 times.
|
273909 | ut_a(file->is_open); |
| 7003 | |||
| 7004 |
1/2✓ Branch 0 taken 273909 times.
✗ Branch 1 not taken.
|
273909 | const page_size_t page_size(space->flags); |
| 7005 |
1/2✓ Branch 0 taken 273909 times.
✗ Branch 1 not taken.
|
273909 | const size_t phy_page_size = page_size.physical(); |
| 7006 | |||
| 7007 | #ifdef UNIV_HOTBACKUP | ||
| 7008 | prev_size = space->size; | ||
| 7009 | |||
| 7010 | ib::trace_1() << "Extending space id : " << space->id | ||
| 7011 | << ", space name : " << space->name | ||
| 7012 | << ", space size : " << space->size | ||
| 7013 | << " pages, page size : " << phy_page_size | ||
| 7014 | << ", to size : " << size; | ||
| 7015 | #endif /* UNIV_HOTBACKUP */ | ||
| 7016 | |||
| 7017 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 273908 times.
|
273909 | if (size <= space->size) { |
| 7018 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | ut_a(file->is_being_extended); |
| 7019 | 1 | file->is_being_extended = false; | |
| 7020 | |||
| 7021 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | complete_io(file, IORequestRead); |
| 7022 | |||
| 7023 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | mutex_release(); |
| 7024 | |||
| 7025 | 1 | return true; | |
| 7026 | } | ||
| 7027 | |||
| 7028 | /* At this point it is safe to release the shard mutex. No | ||
| 7029 | other thread can rename, delete or close the file because | ||
| 7030 | we have set the file->in_use flag. */ | ||
| 7031 | |||
| 7032 |
1/2✓ Branch 0 taken 273908 times.
✗ Branch 1 not taken.
|
273908 | mutex_release(); |
| 7033 | |||
| 7034 | page_no_t pages_added; | ||
| 7035 |
1/2✓ Branch 0 taken 273908 times.
✗ Branch 1 not taken.
|
273908 | os_offset_t node_start = os_file_get_size(file->handle); |
| 7036 | |||
| 7037 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 273908 times.
|
273908 | ut_a(node_start != (os_offset_t)-1); |
| 7038 | |||
| 7039 | /* File first page number */ | ||
| 7040 | 273908 | page_no_t node_first_page = space->size - file->size; | |
| 7041 | |||
| 7042 | /* Number of physical pages in the file */ | ||
| 7043 | 273908 | page_no_t n_node_physical_pages = | |
| 7044 | 273908 | static_cast<page_no_t>(node_start / phy_page_size); | |
| 7045 | |||
| 7046 | /* Number of pages to extend in the file */ | ||
| 7047 | page_no_t n_node_extend; | ||
| 7048 | |||
| 7049 | 273908 | n_node_extend = size - (node_first_page + file->size); | |
| 7050 | |||
| 7051 | /* If we already have enough physical pages to satisfy the | ||
| 7052 | extend request on the file then ignore it */ | ||
| 7053 |
1/2✓ Branch 0 taken 273908 times.
✗ Branch 1 not taken.
|
273908 | if (file->size + n_node_extend > n_node_physical_pages) { |
| 7054 |
4/6✓ Branch 0 taken 273908 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 273907 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
273908 | DBUG_EXECUTE_IF("ib_crash_during_tablespace_extension", DBUG_SUICIDE();); |
| 7055 | |||
| 7056 | os_offset_t len; | ||
| 7057 | 273907 | dberr_t err = DB_SUCCESS; | |
| 7058 | |||
| 7059 | 273907 | len = ((file->size + n_node_extend) * phy_page_size) - node_start; | |
| 7060 | |||
| 7061 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 273907 times.
|
273907 | ut_ad(len > 0); |
| 7062 | |||
| 7063 | #if !defined(UNIV_HOTBACKUP) && defined(UNIV_LINUX) | ||
| 7064 | /* Do not write redo log record for temporary tablespace | ||
| 7065 | and the system tablespace as they don't need to be recreated. | ||
| 7066 | Temporary tablespaces are reinitialized during startup and | ||
| 7067 | hence need not be recovered during recovery. The system | ||
| 7068 | tablespace is neither recreated nor resized and hence we do | ||
| 7069 | not need to redo log any operations on it. */ | ||
| 7070 |
5/6✓ Branch 0 taken 273907 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 183403 times.
✓ Branch 3 taken 90504 times.
✓ Branch 4 taken 183399 times.
✓ Branch 5 taken 90508 times.
|
457310 | if (!recv_recovery_is_on() && space->purpose != FIL_TYPE_TEMPORARY && |
| 7071 |
2/2✓ Branch 0 taken 183399 times.
✓ Branch 1 taken 4 times.
|
183403 | space->id != TRX_SYS_SPACE) { |
| 7072 | /* Write the redo log record for extending the space */ | ||
| 7073 |
1/2✓ Branch 0 taken 183399 times.
✗ Branch 1 not taken.
|
183399 | mtr_t mtr; |
| 7074 |
1/2✓ Branch 0 taken 183399 times.
✗ Branch 1 not taken.
|
183399 | mtr_start(&mtr); |
| 7075 | |||
| 7076 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 183399 times.
|
183399 | ut_ad(node_start > 0); |
| 7077 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 183399 times.
|
183399 | ut_ad(len > 0); |
| 7078 | |||
| 7079 | /* The posix_fallocate() reserves the desired space and updates | ||
| 7080 | the file metadata in the filesystem. On successful execution, any | ||
| 7081 | subsequent attempt to access this newly allocated space will see | ||
| 7082 | it as initialized because of the updated filesystem metadata. | ||
| 7083 | |||
| 7084 | However, the posix_fallocate() call used to allocate space seems | ||
| 7085 | to have an atomicity issue where it can fail after reserving the | ||
| 7086 | space, but before updating the file metadata in the filesystem. | ||
| 7087 | |||
| 7088 | Offset is required to be written in the redo log record to find | ||
| 7089 | out the position in the file where it was extended during space | ||
| 7090 | extend operation. The offset value written in the redo log can | ||
| 7091 | be directly used to find the starting point for initializing | ||
| 7092 | the file during recovery. In case posix_fallocate() crashes as | ||
| 7093 | described above, it will be difficult to find out the old size | ||
| 7094 | of the file and hence it will be difficult to find out the exact | ||
| 7095 | region which needs to be initialized by writing 0's. */ | ||
| 7096 | |||
| 7097 |
1/2✓ Branch 0 taken 183399 times.
✗ Branch 1 not taken.
|
183399 | fil_op_write_space_extend(space->id, node_start, len, &mtr); |
| 7098 | |||
| 7099 |
1/2✓ Branch 0 taken 183399 times.
✗ Branch 1 not taken.
|
183399 | mtr_commit(&mtr); |
| 7100 | |||
| 7101 |
5/8✓ Branch 0 taken 183399 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 183397 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
183399 | DBUG_INJECT_CRASH_WITH_LOG_FLUSH("ib_crash_after_writing_redo_extend", 1); |
| 7102 | |||
| 7103 | /* NOTE: Though against for the Write-Ahead-Log principal, | ||
| 7104 | log_write_up_to() is not needed here, because no file shrinks and | ||
| 7105 | duplicate extending is allowed. And log_write_up_to() here helps | ||
| 7106 | nothing for fallocate() inconsistency. */ | ||
| 7107 | 183397 | } | |
| 7108 | #endif /* !UNIV_HOTBACKUP && UNIV_LINUX */ | ||
| 7109 | |||
| 7110 | #if !defined(NO_FALLOCATE) && defined(UNIV_LINUX) | ||
| 7111 | /* This is required by FusionIO HW/Firmware */ | ||
| 7112 | |||
| 7113 |
1/2✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
|
273905 | int ret = posix_fallocate(file->handle.m_file, node_start, len); |
| 7114 | |||
| 7115 |
3/4✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 273901 times.
|
273905 | DBUG_EXECUTE_IF("ib_posix_fallocate_fail_eintr", ret = EINTR;); |
| 7116 | |||
| 7117 |
2/4✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 273905 times.
|
273905 | DBUG_EXECUTE_IF("ib_posix_fallocate_fail_einval", ret = EINVAL;); |
| 7118 | |||
| 7119 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 273901 times.
|
273905 | if (ret != 0) { |
| 7120 | /* We already pass the valid offset and len in, if EINVAL | ||
| 7121 | is returned, it could only mean that the file system doesn't | ||
| 7122 | support fallocate(), currently one known case is ext3 with O_DIRECT. | ||
| 7123 | |||
| 7124 | Also because above call could be interrupted, in this case, | ||
| 7125 | simply go to plan B by writing zeroes. | ||
| 7126 | |||
| 7127 | Both error messages for above two scenarios are skipped in case | ||
| 7128 | of flooding error messages, because they can be ignored by users. */ | ||
| 7129 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
4 | if (ret != EINTR && ret != EINVAL) { |
| 7130 | ✗ | ib::error(ER_IB_MSG_319) | |
| 7131 | << "posix_fallocate(): Failed to preallocate" | ||
| 7132 | ✗ | " data for file " | |
| 7133 | ✗ | << file->name << ", desired size " << len | |
| 7134 | << " bytes." | ||
| 7135 | ✗ | " Operating system error number " | |
| 7136 | ✗ | << ret | |
| 7137 | << ". Check" | ||
| 7138 | " that the disk is not full or a disk quota" | ||
| 7139 | " exceeded. Make sure the file system supports" | ||
| 7140 | " this function. Refer to your operating system" | ||
| 7141 | " documentation for operating system error code" | ||
| 7142 | ✗ | " information."; | |
| 7143 | } | ||
| 7144 | |||
| 7145 | 4 | err = DB_IO_ERROR; | |
| 7146 | } | ||
| 7147 | #endif /* NO_FALLOCATE || !UNIV_LINUX */ | ||
| 7148 | |||
| 7149 |
6/6✓ Branch 0 taken 273875 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 90496 times.
✓ Branch 3 taken 183379 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 90522 times.
|
273905 | if ((tbsp_extend_and_initialize && !file->atomic_write) || |
| 7150 | err == DB_IO_ERROR) { | ||
| 7151 |
1/2✓ Branch 0 taken 183383 times.
✗ Branch 1 not taken.
|
183383 | err = fil_write_zeros(file, phy_page_size, node_start, len); |
| 7152 | |||
| 7153 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 183383 times.
|
183383 | if (err != DB_SUCCESS) { |
| 7154 | ✗ | ib::warn(ER_IB_MSG_320) | |
| 7155 | ✗ | << "Error while writing " << len << " zeroes to " << file->name | |
| 7156 | ✗ | << " starting at offset " << node_start; | |
| 7157 | } | ||
| 7158 | } | ||
| 7159 | |||
| 7160 | /* Check how many pages actually added */ | ||
| 7161 |
1/2✓ Branch 0 taken 273904 times.
✗ Branch 1 not taken.
|
273905 | os_offset_t end = os_file_get_size(file->handle); |
| 7162 |
3/6✓ Branch 0 taken 273904 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 273905 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 273904 times.
|
273904 | ut_a(end != static_cast<os_offset_t>(-1) && end >= node_start); |
| 7163 | |||
| 7164 | 273904 | success = (end == node_start + len); | |
| 7165 | 273904 | os_has_said_disk_full = !success; | |
| 7166 | |||
| 7167 | 273904 | pages_added = static_cast<page_no_t>(end / phy_page_size); | |
| 7168 | |||
| 7169 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 273905 times.
|
273904 | ut_a(pages_added >= file->size); |
| 7170 | 273905 | pages_added -= file->size; | |
| 7171 | |||
| 7172 | } else { | ||
| 7173 | ✗ | success = true; | |
| 7174 | ✗ | pages_added = n_node_extend; | |
| 7175 | ✗ | os_has_said_disk_full = false; | |
| 7176 | } | ||
| 7177 | |||
| 7178 |
1/2✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
|
273905 | mutex_acquire(); |
| 7179 | |||
| 7180 | 273905 | file->size += pages_added; | |
| 7181 | 273905 | space->size += pages_added; | |
| 7182 | |||
| 7183 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 273905 times.
|
273905 | ut_a(file->is_being_extended); |
| 7184 | 273905 | file->is_being_extended = false; | |
| 7185 | |||
| 7186 |
2/4✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 273905 times.
✗ Branch 3 not taken.
|
273905 | complete_io(file, IORequestWrite); |
| 7187 | |||
| 7188 | #ifndef UNIV_HOTBACKUP | ||
| 7189 | /* Keep the last data file size info up to date, rounded to | ||
| 7190 | full megabytes */ | ||
| 7191 | 273905 | page_no_t pages_per_mb = | |
| 7192 | 273905 | static_cast<page_no_t>((1024 * 1024) / phy_page_size); | |
| 7193 | |||
| 7194 | 273905 | page_no_t size_in_pages = ((file->size / pages_per_mb) * pages_per_mb); | |
| 7195 | |||
| 7196 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 273901 times.
|
273905 | if (space->id == TRX_SYS_SPACE) { |
| 7197 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | srv_sys_space.set_last_file_size(size_in_pages); |
| 7198 |
3/4✓ Branch 0 taken 273901 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90504 times.
✓ Branch 3 taken 183397 times.
|
273901 | } else if (fsp_is_system_temporary(space->id)) { |
| 7199 |
1/2✓ Branch 0 taken 90504 times.
✗ Branch 1 not taken.
|
90504 | srv_tmp_space.set_last_file_size(size_in_pages); |
| 7200 | } | ||
| 7201 | #else /* !UNIV_HOTBACKUP */ | ||
| 7202 | ib::trace_2() << "Extended space : " << space->name << " from " << prev_size | ||
| 7203 | << " pages to " << space->size << " pages " | ||
| 7204 | << ", desired space size : " << size << " pages"; | ||
| 7205 | #endif /* !UNIV_HOTBACKUP */ | ||
| 7206 | |||
| 7207 |
1/2✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
|
273905 | space_flush(space->id); |
| 7208 | |||
| 7209 |
1/2✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
|
273905 | mutex_release(); |
| 7210 | |||
| 7211 |
2/6✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 273905 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
273905 | DBUG_EXECUTE_IF("fil_crash_after_extend", DBUG_SUICIDE();); |
| 7212 | 273905 | return success; | |
| 7213 | } | ||
| 7214 | |||
| 7215 | /** Try to extend a tablespace if it is smaller than the specified size. | ||
| 7216 | @param[in,out] space Tablespace ID | ||
| 7217 | @param[in] size desired size in pages | ||
| 7218 | @return whether the tablespace is at least as big as requested */ | ||
| 7219 | 273924 | bool fil_space_extend(fil_space_t *space, page_no_t size) { | |
| 7220 | 273924 | auto shard = fil_system->shard_by_id(space->id); | |
| 7221 | |||
| 7222 | 273924 | return shard->space_extend(space, size); | |
| 7223 | } | ||
| 7224 | |||
| 7225 | #ifdef UNIV_HOTBACKUP | ||
| 7226 | /** Extends all tablespaces to the size stored in the space header. During the | ||
| 7227 | mysqlbackup --apply-log phase we extended the spaces on-demand so that log | ||
| 7228 | records could be applied, but that may have left spaces still too small | ||
| 7229 | compared to the size stored in the space header. */ | ||
| 7230 | void Fil_shard::meb_extend_tablespaces_to_stored_len() { | ||
| 7231 | ut_ad(mutex_owned()); | ||
| 7232 | |||
| 7233 | byte *buf = static_cast<byte *>( | ||
| 7234 | ut::malloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, UNIV_PAGE_SIZE)); | ||
| 7235 | |||
| 7236 | ut_a(buf != nullptr); | ||
| 7237 | |||
| 7238 | for (auto &elem : m_spaces) { | ||
| 7239 | auto space = elem.second; | ||
| 7240 | |||
| 7241 | ut_a(space->purpose == FIL_TYPE_TABLESPACE); | ||
| 7242 | |||
| 7243 | /* No need to protect with a mutex, because this is | ||
| 7244 | a single-threaded operation */ | ||
| 7245 | |||
| 7246 | mutex_release(); | ||
| 7247 | |||
| 7248 | dberr_t error; | ||
| 7249 | |||
| 7250 | const page_size_t page_size(space->flags); | ||
| 7251 | |||
| 7252 | error = fil_read(page_id_t(space->id, 0), page_size, 0, | ||
| 7253 | page_size.physical(), buf); | ||
| 7254 | |||
| 7255 | ut_a(error == DB_SUCCESS); | ||
| 7256 | |||
| 7257 | ulint size_in_header; | ||
| 7258 | |||
| 7259 | size_in_header = fsp_header_get_field(buf, FSP_SIZE); | ||
| 7260 | |||
| 7261 | bool success; | ||
| 7262 | |||
| 7263 | success = space_extend(space, size_in_header); | ||
| 7264 | |||
| 7265 | if (!success) { | ||
| 7266 | ib::error(ER_IB_MSG_321) | ||
| 7267 | << "Could not extend the tablespace of " << space->name | ||
| 7268 | << " to the size stored in" | ||
| 7269 | " header, " | ||
| 7270 | << size_in_header | ||
| 7271 | << " pages;" | ||
| 7272 | " size after extension " | ||
| 7273 | << 0 | ||
| 7274 | << " pages. Check that you have free disk" | ||
| 7275 | " space and retry!"; | ||
| 7276 | |||
| 7277 | ut_a(success); | ||
| 7278 | } | ||
| 7279 | |||
| 7280 | mutex_acquire(); | ||
| 7281 | } | ||
| 7282 | |||
| 7283 | ut::free(buf); | ||
| 7284 | } | ||
| 7285 | |||
| 7286 | /** Extends all tablespaces to the size stored in the space header. During the | ||
| 7287 | mysqlbackup --apply-log phase we extended the spaces on-demand so that log | ||
| 7288 | records could be applied, but that may have left spaces still too small | ||
| 7289 | compared to the size stored in the space header. */ | ||
| 7290 | void meb_extend_tablespaces_to_stored_len() { | ||
| 7291 | fil_system->meb_extend_tablespaces_to_stored_len(); | ||
| 7292 | } | ||
| 7293 | |||
| 7294 | bool meb_is_redo_log_only_restore = false; | ||
| 7295 | |||
| 7296 | /** Determine if file is intermediate / temporary. These files are | ||
| 7297 | created during reorganize partition, rename tables, add / drop columns etc. | ||
| 7298 | @param[in] filepath absolute / relative or simply file name | ||
| 7299 | @retvalue true if it is intermediate file | ||
| 7300 | @retvalue false if it is normal file */ | ||
| 7301 | bool meb_is_intermediate_file(const std::string &filepath) { | ||
| 7302 | std::string file_name = filepath; | ||
| 7303 | |||
| 7304 | { | ||
| 7305 | /** If its redo only restore, apply log needs to got through the | ||
| 7306 | intermediate steps to apply a ddl. | ||
| 7307 | Some of these operation might result in intermediate files. | ||
| 7308 | */ | ||
| 7309 | if (meb_is_redo_log_only_restore) return false; | ||
| 7310 | /* extract file name from relative or absolute file name */ | ||
| 7311 | auto pos = file_name.rfind(OS_PATH_SEPARATOR); | ||
| 7312 | |||
| 7313 | if (pos != std::string::npos) { | ||
| 7314 | ++pos; | ||
| 7315 | file_name = file_name.substr(pos); | ||
| 7316 | } | ||
| 7317 | } | ||
| 7318 | |||
| 7319 | transform(file_name.begin(), file_name.end(), file_name.begin(), ::tolower); | ||
| 7320 | |||
| 7321 | if (file_name[0] != '#') { | ||
| 7322 | auto pos = file_name.rfind("#tmp#.ibd"); | ||
| 7323 | if (pos != std::string::npos) { | ||
| 7324 | return true; | ||
| 7325 | } else { | ||
| 7326 | return false; /* normal file name */ | ||
| 7327 | } | ||
| 7328 | } | ||
| 7329 | |||
| 7330 | static std::vector<std::string> prefixes = {"#sql-", "#sql2-", "#tmp#", | ||
| 7331 | "#ren#"}; | ||
| 7332 | |||
| 7333 | /* search for the unsupported patterns */ | ||
| 7334 | for (const auto &prefix : prefixes) { | ||
| 7335 | if (Fil_path::has_prefix(file_name, prefix)) { | ||
| 7336 | return true; | ||
| 7337 | } | ||
| 7338 | } | ||
| 7339 | |||
| 7340 | return false; | ||
| 7341 | } | ||
| 7342 | |||
| 7343 | /** Return the space ID based of the remote general tablespace name. | ||
| 7344 | This is a wrapper over fil_space_get_id_by_name() method. it means, | ||
| 7345 | the tablespace must be found in the tablespace memory cache. | ||
| 7346 | This method extracts the tablespace name from input parameters and checks if | ||
| 7347 | it has been loaded in memory cache through either any of the remote general | ||
| 7348 | tablespaces directories identified at the time memory cache created. | ||
| 7349 | @param[in, out] tablespace Tablespace name | ||
| 7350 | @return space ID if tablespace found, SPACE_UNKNOWN if not found. */ | ||
| 7351 | space_id_t meb_fil_space_get_rem_gen_ts_id_by_name(std::string &tablespace) { | ||
| 7352 | space_id_t space_id = SPACE_UNKNOWN; | ||
| 7353 | |||
| 7354 | for (auto newpath : rem_gen_ts_dirs) { | ||
| 7355 | auto pos = tablespace.rfind(OS_PATH_SEPARATOR); | ||
| 7356 | |||
| 7357 | if (pos == std::string::npos) { | ||
| 7358 | break; | ||
| 7359 | } | ||
| 7360 | |||
| 7361 | newpath += tablespace.substr(pos); | ||
| 7362 | |||
| 7363 | space_id = fil_space_get_id_by_name(newpath.c_str()); | ||
| 7364 | |||
| 7365 | if (space_id != SPACE_UNKNOWN) { | ||
| 7366 | tablespace = newpath; | ||
| 7367 | break; | ||
| 7368 | } | ||
| 7369 | } | ||
| 7370 | |||
| 7371 | return space_id; | ||
| 7372 | } | ||
| 7373 | |||
| 7374 | /** Tablespace item during recovery */ | ||
| 7375 | struct MEB_file_name { | ||
| 7376 | /** Constructor */ | ||
| 7377 | MEB_file_name(std::string name, bool deleted) | ||
| 7378 | : m_name(name), m_space(), m_deleted(deleted) {} | ||
| 7379 | |||
| 7380 | /** Tablespace file name (MLOG_FILE_NAME) */ | ||
| 7381 | std::string m_name; | ||
| 7382 | |||
| 7383 | /** Tablespace object (NULL if not valid or not found) */ | ||
| 7384 | fil_space_t *m_space; | ||
| 7385 | |||
| 7386 | /** Whether the tablespace has been deleted */ | ||
| 7387 | bool m_deleted; | ||
| 7388 | }; | ||
| 7389 | |||
| 7390 | /** Map of dirty tablespaces during recovery */ | ||
| 7391 | using MEB_recv_spaces = | ||
| 7392 | std::map<space_id_t, MEB_file_name, std::less<space_id_t>, | ||
| 7393 | ut::allocator<std::pair<const space_id_t, MEB_file_name>>>; | ||
| 7394 | |||
| 7395 | static MEB_recv_spaces recv_spaces; | ||
| 7396 | |||
| 7397 | /** Checks if MEB has loaded this space for reovery. | ||
| 7398 | @param[in] space_id Tablespace ID | ||
| 7399 | @return true if the space_id is loaded */ | ||
| 7400 | bool meb_is_space_loaded(const space_id_t space_id) { | ||
| 7401 | return (recv_spaces.find(space_id) != recv_spaces.end()); | ||
| 7402 | } | ||
| 7403 | |||
| 7404 | /** Set the keys for an encrypted tablespace. | ||
| 7405 | @param[in] space Tablespace for which to set the key */ | ||
| 7406 | static void meb_set_encryption_key(const fil_space_t *space) { | ||
| 7407 | ut_ad(FSP_FLAGS_GET_ENCRYPTION(space->flags)); | ||
| 7408 | |||
| 7409 | for (auto &key : *recv_sys->keys) { | ||
| 7410 | if (key.space_id != space->id) { | ||
| 7411 | continue; | ||
| 7412 | } | ||
| 7413 | |||
| 7414 | dberr_t err; | ||
| 7415 | |||
| 7416 | err = fil_set_encryption(space->id, Encryption::AES, key.ptr, key.iv); | ||
| 7417 | |||
| 7418 | if (err != DB_SUCCESS) { | ||
| 7419 | ib::error(ER_IB_MSG_322) << "Can't set encryption information" | ||
| 7420 | << " for tablespace" << space->name << "!"; | ||
| 7421 | } | ||
| 7422 | |||
| 7423 | ut::free(key.iv); | ||
| 7424 | ut::free(key.ptr); | ||
| 7425 | |||
| 7426 | key.iv = nullptr; | ||
| 7427 | key.ptr = nullptr; | ||
| 7428 | key.space_id = 0; | ||
| 7429 | } | ||
| 7430 | } | ||
| 7431 | |||
| 7432 | /** Process a file name passed as an input | ||
| 7433 | Wrapper around meb_name_process() | ||
| 7434 | @param[in,out] name absolute path of tablespace file | ||
| 7435 | @param[in] space_id The tablespace ID | ||
| 7436 | @param[in] deleted true if MLOG_FILE_DELETE */ | ||
| 7437 | void Fil_system::meb_name_process(char *name, space_id_t space_id, | ||
| 7438 | bool deleted) { | ||
| 7439 | ut_ad(space_id != TRX_SYS_SPACE); | ||
| 7440 | |||
| 7441 | /* We will also insert space=nullptr into the map, so that | ||
| 7442 | further checks can ensure that a MLOG_FILE_NAME record was | ||
| 7443 | scanned before applying any page records for the space_id. */ | ||
| 7444 | |||
| 7445 | Fil_path::normalize(name); | ||
| 7446 | |||
| 7447 | size_t len = std::strlen(name); | ||
| 7448 | |||
| 7449 | MEB_file_name fname(std::string(name, len - 1), deleted); | ||
| 7450 | |||
| 7451 | auto p = recv_spaces.insert(std::make_pair(space_id, fname)); | ||
| 7452 | |||
| 7453 | ut_ad(p.first->first == space_id); | ||
| 7454 | |||
| 7455 | MEB_file_name &f = p.first->second; | ||
| 7456 | |||
| 7457 | if (deleted) { | ||
| 7458 | /* Got MLOG_FILE_DELETE */ | ||
| 7459 | |||
| 7460 | if (!p.second && !f.m_deleted) { | ||
| 7461 | f.m_deleted = true; | ||
| 7462 | |||
| 7463 | if (f.m_space != nullptr) { | ||
| 7464 | f.m_space = nullptr; | ||
| 7465 | } | ||
| 7466 | } | ||
| 7467 | |||
| 7468 | ut_ad(f.m_space == nullptr); | ||
| 7469 | |||
| 7470 | } else if (p.second || f.m_name != fname.m_name) { | ||
| 7471 | fil_space_t *space; | ||
| 7472 | |||
| 7473 | /* Check if the tablespace file exists and contains | ||
| 7474 | the space_id. If not, ignore the file after displaying | ||
| 7475 | a note. Abort if there are multiple files with the | ||
| 7476 | same space_id. */ | ||
| 7477 | |||
| 7478 | switch (ibd_open_for_recovery(space_id, name, space)) { | ||
| 7479 | case FIL_LOAD_OK: | ||
| 7480 | ut_ad(space != nullptr); | ||
| 7481 | |||
| 7482 | /* For encrypted tablespace, set key and iv. */ | ||
| 7483 | if (FSP_FLAGS_GET_ENCRYPTION(space->flags) && | ||
| 7484 | recv_sys->keys != nullptr) { | ||
| 7485 | meb_set_encryption_key(space); | ||
| 7486 | } | ||
| 7487 | |||
| 7488 | if (f.m_space == nullptr || f.m_space == space) { | ||
| 7489 | f.m_name = fname.m_name; | ||
| 7490 | f.m_space = space; | ||
| 7491 | f.m_deleted = false; | ||
| 7492 | |||
| 7493 | } else { | ||
| 7494 | ib::error(ER_IB_MSG_323) | ||
| 7495 | << "Tablespace " << space_id << " has been found in two places: '" | ||
| 7496 | << f.m_name << "' and '" << name | ||
| 7497 | << "'." | ||
| 7498 | " You must delete one of them."; | ||
| 7499 | |||
| 7500 | recv_sys->found_corrupt_fs = true; | ||
| 7501 | } | ||
| 7502 | break; | ||
| 7503 | |||
| 7504 | case FIL_LOAD_ID_CHANGED: | ||
| 7505 | ut_ad(space == nullptr); | ||
| 7506 | |||
| 7507 | ib::trace_1() << "Ignoring file " << name << " for space-id mismatch " | ||
| 7508 | << space_id; | ||
| 7509 | break; | ||
| 7510 | |||
| 7511 | case FIL_LOAD_NOT_FOUND: | ||
| 7512 | /* No matching tablespace was found; maybe it | ||
| 7513 | was renamed, and we will find a subsequent | ||
| 7514 | MLOG_FILE_* record. */ | ||
| 7515 | ut_ad(space == nullptr); | ||
| 7516 | break; | ||
| 7517 | |||
| 7518 | case FIL_LOAD_INVALID: | ||
| 7519 | ut_ad(space == nullptr); | ||
| 7520 | |||
| 7521 | ib::warn(ER_IB_MSG_324) << "Invalid tablespace " << name; | ||
| 7522 | break; | ||
| 7523 | |||
| 7524 | case FIL_LOAD_MISMATCH: | ||
| 7525 | ut_ad(space == nullptr); | ||
| 7526 | break; | ||
| 7527 | case FIL_LOAD_DBWLR_CORRUPTION: | ||
| 7528 | ut_ad(space == nullptr); | ||
| 7529 | break; | ||
| 7530 | } | ||
| 7531 | } | ||
| 7532 | } | ||
| 7533 | |||
| 7534 | /** Process a file name passed as an input | ||
| 7535 | Wrapper around meb_name_process() | ||
| 7536 | @param[in] name absolute path of tablespace file | ||
| 7537 | @param[in] space_id the tablespace ID */ | ||
| 7538 | void meb_fil_name_process(const char *name, space_id_t space_id) { | ||
| 7539 | char *file_name = static_cast<char *>(mem_strdup(name)); | ||
| 7540 | |||
| 7541 | fil_system->meb_name_process(file_name, space_id, false); | ||
| 7542 | |||
| 7543 | ut::free(file_name); | ||
| 7544 | } | ||
| 7545 | |||
| 7546 | /** Test, if a file path name contains a back-link ("../"). | ||
| 7547 | We assume a path to a file. So we don't check for a trailing "/..". | ||
| 7548 | @param[in] path path to check | ||
| 7549 | @return whether the path contains a back-link. | ||
| 7550 | */ | ||
| 7551 | static bool meb_has_back_link(const std::string &path) { | ||
| 7552 | #ifdef _WIN32 | ||
| 7553 | static const std::string DOT_DOT_SLASH = "..\\"; | ||
| 7554 | static const std::string SLASH_DOT_DOT_SLASH = "\\..\\"; | ||
| 7555 | #else | ||
| 7556 | static const std::string DOT_DOT_SLASH = "../"; | ||
| 7557 | static const std::string SLASH_DOT_DOT_SLASH = "/../"; | ||
| 7558 | #endif /* _WIN32 */ | ||
| 7559 | return ((0 == path.compare(0, 3, DOT_DOT_SLASH)) || | ||
| 7560 | (std::string::npos != path.find(SLASH_DOT_DOT_SLASH))); | ||
| 7561 | } | ||
| 7562 | |||
| 7563 | /** Parse a file name retrieved from a MLOG_FILE_* record, | ||
| 7564 | and return the absolute file path corresponds to backup dir | ||
| 7565 | as well as in the form of database/tablespace | ||
| 7566 | @param[in] name path emitted by the redo log | ||
| 7567 | @param[in] flags flags emitted by the redo log | ||
| 7568 | @param[in] space_id space_id emmited by the redo log | ||
| 7569 | @param[out] absolute_path absolute path of tablespace | ||
| 7570 | corresponds to target dir | ||
| 7571 | @param[out] tablespace_name name in the form of database/table */ | ||
| 7572 | static void meb_make_abs_file_path(const std::string &name, uint32_t flags, | ||
| 7573 | space_id_t space_id, | ||
| 7574 | std::string &absolute_path, | ||
| 7575 | std::string &tablespace_name) { | ||
| 7576 | Datafile df; | ||
| 7577 | std::string file_name = name; | ||
| 7578 | |||
| 7579 | /* If the tablespace path name is absolute or has back-links ("../"), | ||
| 7580 | we assume, that it is located outside of datadir. */ | ||
| 7581 | if (Fil_path::is_absolute_path(file_name.c_str()) || | ||
| 7582 | (meb_has_back_link(file_name) && !replay_in_datadir)) { | ||
| 7583 | if (replay_in_datadir) { | ||
| 7584 | /* This is an apply-log in the restored datadir. Take the path as is. */ | ||
| 7585 | df.set_filepath(file_name.c_str()); | ||
| 7586 | } else { | ||
| 7587 | /* This is an apply-log in backup_dir/datadir. Get the file inside. */ | ||
| 7588 | auto pos = file_name.rfind(OS_PATH_SEPARATOR); | ||
| 7589 | |||
| 7590 | /* if it is file per tablespace, then include the schema | ||
| 7591 | directory as well */ | ||
| 7592 | if (fsp_is_file_per_table(space_id, flags) && pos != std::string::npos) { | ||
| 7593 | pos = file_name.rfind(OS_PATH_SEPARATOR, pos - 1); | ||
| 7594 | } | ||
| 7595 | |||
| 7596 | if (pos == std::string::npos) { | ||
| 7597 | ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_325) | ||
| 7598 | << "Could not extract the tablespace" | ||
| 7599 | << " file name from the in the path : " << name; | ||
| 7600 | } | ||
| 7601 | |||
| 7602 | ++pos; | ||
| 7603 | |||
| 7604 | file_name = file_name.substr(pos); | ||
| 7605 | |||
| 7606 | df.make_filepath(MySQL_datadir_path, file_name.c_str(), IBD); | ||
| 7607 | } | ||
| 7608 | |||
| 7609 | } else { | ||
| 7610 | /* This is an apply-log with a relative path, either in the restored | ||
| 7611 | datadir, or in backup_dir/datadir. If in the restored datadir, the | ||
| 7612 | path might start with "../" to reach outside of datadir. */ | ||
| 7613 | auto pos = file_name.find(OS_PATH_SEPARATOR); | ||
| 7614 | |||
| 7615 | /* Remove the cur dir from the path as this will cause the | ||
| 7616 | path name mismatch when we try to find out the space_id based | ||
| 7617 | on tablespace name */ | ||
| 7618 | |||
| 7619 | if (file_name.substr(0, pos) == ".") { | ||
| 7620 | ++pos; | ||
| 7621 | file_name = file_name.substr(pos); | ||
| 7622 | } | ||
| 7623 | |||
| 7624 | /* make_filepath() does not prepend the directory, if the file name | ||
| 7625 | starts with "../". Prepend it unconditionally here. */ | ||
| 7626 | file_name.insert(0, 1, OS_PATH_SEPARATOR); | ||
| 7627 | file_name.insert(0, MySQL_datadir_path); | ||
| 7628 | |||
| 7629 | df.make_filepath(nullptr, file_name.c_str(), IBD); | ||
| 7630 | } | ||
| 7631 | |||
| 7632 | df.set_flags(flags); | ||
| 7633 | df.set_space_id(space_id); | ||
| 7634 | df.set_name(nullptr); | ||
| 7635 | |||
| 7636 | absolute_path = df.filepath(); | ||
| 7637 | |||
| 7638 | tablespace_name = df.name(); | ||
| 7639 | } | ||
| 7640 | |||
| 7641 | /** Process a MLOG_FILE_CREATE redo record. | ||
| 7642 | @param[in] page_id Page id of the redo log record | ||
| 7643 | @param[in] flags Tablespace flags | ||
| 7644 | @param[in] name Tablespace filename */ | ||
| 7645 | static void meb_tablespace_redo_create(const page_id_t &page_id, uint32_t flags, | ||
| 7646 | const char *name) { | ||
| 7647 | std::string abs_file_path; | ||
| 7648 | std::string tablespace_name; | ||
| 7649 | |||
| 7650 | meb_make_abs_file_path(name, flags, page_id.space(), abs_file_path, | ||
| 7651 | tablespace_name); | ||
| 7652 | |||
| 7653 | if (meb_is_intermediate_file(abs_file_path.c_str()) || | ||
| 7654 | fil_space_get(page_id.space()) || | ||
| 7655 | fil_space_get_id_by_name(tablespace_name.c_str()) != SPACE_UNKNOWN || | ||
| 7656 | meb_fil_space_get_rem_gen_ts_id_by_name(tablespace_name) != | ||
| 7657 | SPACE_UNKNOWN) { | ||
| 7658 | /* Don't create table while :- | ||
| 7659 | 1. scanning the redo logs during backup | ||
| 7660 | 2. apply-log on a partial backup | ||
| 7661 | 3. if it is intermediate file | ||
| 7662 | 4. tablespace is already loaded in memory | ||
| 7663 | 5. tablespace is a remote general tablespace which is | ||
| 7664 | already loaded for recovery/apply-log from different | ||
| 7665 | directory path */ | ||
| 7666 | |||
| 7667 | ib::trace_1() << "Ignoring the log record. No need to " | ||
| 7668 | << "create the tablespace : " << abs_file_path; | ||
| 7669 | } else { | ||
| 7670 | auto it = recv_spaces.find(page_id.space()); | ||
| 7671 | |||
| 7672 | if (it == recv_spaces.end() || it->second.m_name != abs_file_path) { | ||
| 7673 | ib::trace_1() << "Creating the tablespace : " << abs_file_path | ||
| 7674 | << ", space_id : " << page_id.space(); | ||
| 7675 | |||
| 7676 | dberr_t ret = fil_ibd_create(page_id.space(), tablespace_name.c_str(), | ||
| 7677 | abs_file_path.c_str(), flags, | ||
| 7678 | FIL_IBD_FILE_INITIAL_SIZE); | ||
| 7679 | |||
| 7680 | if (ret != DB_SUCCESS) { | ||
| 7681 | ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_326) | ||
| 7682 | << "Could not create the tablespace : " << abs_file_path | ||
| 7683 | << " with space Id : " << page_id.space(); | ||
| 7684 | } | ||
| 7685 | } | ||
| 7686 | } | ||
| 7687 | } | ||
| 7688 | |||
| 7689 | /** Process a MLOG_FILE_RENAME redo record. | ||
| 7690 | @param[in] page_id Page id of the redo log record | ||
| 7691 | @param[in] from_name Tablespace from filename | ||
| 7692 | @param[in] to_name Tablespace to filename */ | ||
| 7693 | static void meb_tablespace_redo_rename(const page_id_t &page_id, | ||
| 7694 | const char *from_name, | ||
| 7695 | const char *to_name) { | ||
| 7696 | std::string abs_to_path; | ||
| 7697 | std::string abs_from_path; | ||
| 7698 | std::string tablespace_name; | ||
| 7699 | |||
| 7700 | meb_make_abs_file_path(from_name, 0, page_id.space(), abs_from_path, | ||
| 7701 | tablespace_name); | ||
| 7702 | |||
| 7703 | meb_make_abs_file_path(to_name, 0, page_id.space(), abs_to_path, | ||
| 7704 | tablespace_name); | ||
| 7705 | |||
| 7706 | char *new_name = nullptr; | ||
| 7707 | |||
| 7708 | if (meb_is_intermediate_file(from_name) || | ||
| 7709 | meb_is_intermediate_file(to_name) || | ||
| 7710 | fil_space_get_id_by_name(tablespace_name.c_str()) != SPACE_UNKNOWN || | ||
| 7711 | meb_fil_space_get_rem_gen_ts_id_by_name(tablespace_name) != | ||
| 7712 | SPACE_UNKNOWN || | ||
| 7713 | fil_space_get(page_id.space()) == nullptr) { | ||
| 7714 | /* Don't rename table while : | ||
| 7715 | 1. Scanning the redo logs during backup | ||
| 7716 | 2. Apply-log on a partial backup | ||
| 7717 | 3. Either of old or new tables are intermediate table | ||
| 7718 | 4. The new name is already loaded for recovery/apply-log | ||
| 7719 | 5. The new name is a remote general tablespace which is | ||
| 7720 | already loaded for recovery/apply-log from different | ||
| 7721 | directory path | ||
| 7722 | 6. Tablespace is not yet loaded in memory. | ||
| 7723 | This will prevent unintended renames during recovery. */ | ||
| 7724 | |||
| 7725 | ib::trace_1() << "Ignoring the log record. " | ||
| 7726 | << "No need to rename tablespace"; | ||
| 7727 | |||
| 7728 | return; | ||
| 7729 | |||
| 7730 | } else { | ||
| 7731 | ib::trace_1() << "Renaming space id : " << page_id.space() | ||
| 7732 | << ", old tablespace name : " << from_name | ||
| 7733 | << " to new tablespace name : " << to_name; | ||
| 7734 | |||
| 7735 | new_name = static_cast<char *>(mem_strdup(abs_to_path.c_str())); | ||
| 7736 | } | ||
| 7737 | |||
| 7738 | meb_fil_name_process(from_name, page_id.space()); | ||
| 7739 | meb_fil_name_process(new_name, page_id.space()); | ||
| 7740 | |||
| 7741 | if (!fil_op_replay_rename(page_id, abs_from_path.c_str(), | ||
| 7742 | abs_to_path.c_str())) { | ||
| 7743 | recv_sys->found_corrupt_fs = true; | ||
| 7744 | } | ||
| 7745 | |||
| 7746 | meb_fil_name_process(to_name, page_id.space()); | ||
| 7747 | |||
| 7748 | ut::free(new_name); | ||
| 7749 | } | ||
| 7750 | |||
| 7751 | /** Process a MLOG_FILE_DELETE redo record. | ||
| 7752 | @param[in] page_id Page id of the redo log record | ||
| 7753 | @param[in] name Tablespace filename */ | ||
| 7754 | static void meb_tablespace_redo_delete(const page_id_t &page_id, | ||
| 7755 | const char *name) { | ||
| 7756 | std::string abs_file_path; | ||
| 7757 | std::string tablespace_name; | ||
| 7758 | |||
| 7759 | meb_make_abs_file_path(name, 0, page_id.space(), abs_file_path, | ||
| 7760 | tablespace_name); | ||
| 7761 | |||
| 7762 | char *file_name = static_cast<char *>(mem_strdup(name)); | ||
| 7763 | |||
| 7764 | fil_system->meb_name_process(file_name, page_id.space(), true); | ||
| 7765 | |||
| 7766 | if (fil_space_get(page_id.space())) { | ||
| 7767 | ib::trace_1() << "Deleting the tablespace : " << abs_file_path | ||
| 7768 | << ", space_id : " << page_id.space(); | ||
| 7769 | dberr_t err = | ||
| 7770 | fil_delete_tablespace(page_id.space(), BUF_REMOVE_FLUSH_NO_WRITE); | ||
| 7771 | |||
| 7772 | ut_a(err == DB_SUCCESS); | ||
| 7773 | } | ||
| 7774 | |||
| 7775 | ut::free(file_name); | ||
| 7776 | } | ||
| 7777 | |||
| 7778 | #endif /* UNIV_HOTBACKUP */ | ||
| 7779 | |||
| 7780 | /*========== RESERVE FREE EXTENTS (for a B-tree split, for example) ===*/ | ||
| 7781 | |||
| 7782 | /** Tries to reserve free extents in a file space. | ||
| 7783 | @param[in] space_id Tablespace ID | ||
| 7784 | @param[in] n_free_now Number of free extents now | ||
| 7785 | @param[in] n_to_reserve How many one wants to reserve | ||
| 7786 | @return true if succeed */ | ||
| 7787 | 8945066 | bool fil_space_reserve_free_extents(space_id_t space_id, ulint n_free_now, | |
| 7788 | ulint n_to_reserve) { | ||
| 7789 | 8945066 | auto shard = fil_system->shard_by_id(space_id); | |
| 7790 | |||
| 7791 | 8945066 | shard->mutex_acquire(); | |
| 7792 | |||
| 7793 | 8945066 | fil_space_t *space = shard->get_space_by_id(space_id); | |
| 7794 | |||
| 7795 | bool success; | ||
| 7796 | |||
| 7797 |
2/2✓ Branch 0 taken 4308 times.
✓ Branch 1 taken 8940757 times.
|
8945065 | if (space->n_reserved_extents + n_to_reserve > n_free_now) { |
| 7798 | 4308 | success = false; | |
| 7799 | } else { | ||
| 7800 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8940756 times.
|
8940757 | ut_a(n_to_reserve < std::numeric_limits<uint32_t>::max()); |
| 7801 | 8940756 | space->n_reserved_extents += (uint32_t)n_to_reserve; | |
| 7802 | 8940756 | success = true; | |
| 7803 | } | ||
| 7804 | |||
| 7805 | 8945064 | shard->mutex_release(); | |
| 7806 | |||
| 7807 | 8945066 | return success; | |
| 7808 | } | ||
| 7809 | |||
| 7810 | /** Releases free extents in a file space. | ||
| 7811 | @param[in] space_id Tablespace ID | ||
| 7812 | @param[in] n_reserved How many were reserved */ | ||
| 7813 | 10490416 | void fil_space_release_free_extents(space_id_t space_id, ulint n_reserved) { | |
| 7814 | 10490416 | auto shard = fil_system->shard_by_id(space_id); | |
| 7815 | |||
| 7816 | 10490420 | shard->mutex_acquire(); | |
| 7817 | |||
| 7818 | 10490418 | fil_space_t *space = shard->get_space_by_id(space_id); | |
| 7819 | |||
| 7820 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10490418 times.
|
10490417 | ut_a(n_reserved < std::numeric_limits<uint32_t>::max()); |
| 7821 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10490416 times.
|
10490418 | ut_a(space->n_reserved_extents >= n_reserved); |
| 7822 | |||
| 7823 | 10490416 | space->n_reserved_extents -= (uint32_t)n_reserved; | |
| 7824 | |||
| 7825 | 10490416 | shard->mutex_release(); | |
| 7826 | 10490419 | } | |
| 7827 | |||
| 7828 | /** Gets the number of reserved extents. If the database is silent, this number | ||
| 7829 | should be zero. | ||
| 7830 | @param[in] space_id Tablespace ID | ||
| 7831 | @return the number of reserved extents */ | ||
| 7832 | 1889980 | ulint fil_space_get_n_reserved_extents(space_id_t space_id) { | |
| 7833 | 1889980 | auto shard = fil_system->shard_by_id(space_id); | |
| 7834 | |||
| 7835 | 1889982 | shard->mutex_acquire(); | |
| 7836 | |||
| 7837 | 1889981 | fil_space_t *space = shard->get_space_by_id(space_id); | |
| 7838 | |||
| 7839 | 1889982 | ulint n = space->n_reserved_extents; | |
| 7840 | |||
| 7841 | 1889982 | shard->mutex_release(); | |
| 7842 | |||
| 7843 | 1889982 | return n; | |
| 7844 | } | ||
| 7845 | |||
| 7846 | /*============================ FILE I/O ================================*/ | ||
| 7847 | |||
| 7848 | 63919162 | bool Fil_shard::prepare_file_for_io(fil_node_t *file) { | |
| 7849 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63919817 times.
|
63919162 | ut_ad(mutex_owned()); |
| 7850 | |||
| 7851 | 63919817 | fil_space_t *space = file->space; | |
| 7852 | |||
| 7853 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63919964 times.
|
63919817 | if (space->is_deleted()) { |
| 7854 | ✗ | return false; | |
| 7855 | } | ||
| 7856 | |||
| 7857 |
2/2✓ Branch 0 taken 276820 times.
✓ Branch 1 taken 63643144 times.
|
63919964 | if (!file->is_open) { |
| 7858 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 276820 times.
|
276820 | ut_a(file->n_pending_ios == 0); |
| 7859 | |||
| 7860 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 276816 times.
|
276820 | if (!open_file(file)) { |
| 7861 | ✗ | return false; | |
| 7862 | } | ||
| 7863 | } | ||
| 7864 |
2/2✓ Branch 0 taken 56952949 times.
✓ Branch 1 taken 6967011 times.
|
63919960 | if (file->n_pending_ios == 0) { |
| 7865 | 56952949 | remove_from_LRU(file); | |
| 7866 | } | ||
| 7867 | |||
| 7868 | 63919737 | ++file->n_pending_ios; | |
| 7869 | |||
| 7870 | /* The file can't be in the LRU list. */ | ||
| 7871 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63920104 times.
|
63919737 | ut_ad(!ut_list_exists(m_LRU, file)); |
| 7872 | |||
| 7873 | 63920104 | return true; | |
| 7874 | } | ||
| 7875 | |||
| 7876 | /** If the tablespace is not on the unflushed list, add it. | ||
| 7877 | @param[in,out] space Tablespace to add */ | ||
| 7878 | 16006847 | void Fil_shard::add_to_unflushed_list(fil_space_t *space) { | |
| 7879 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16006912 times.
|
16006847 | ut_ad(mutex_owned()); |
| 7880 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16006907 times.
|
16006912 | ut_a(space->purpose != FIL_TYPE_TEMPORARY); |
| 7881 | |||
| 7882 |
2/2✓ Branch 0 taken 7559625 times.
✓ Branch 1 taken 8447282 times.
|
16006907 | if (!space->is_in_unflushed_spaces) { |
| 7883 | 7559625 | space->is_in_unflushed_spaces = true; | |
| 7884 | |||
| 7885 | 7559625 | UT_LIST_ADD_FIRST(m_unflushed_spaces, space); | |
| 7886 | } | ||
| 7887 | 16006970 | } | |
| 7888 | |||
| 7889 | /** Note that a write IO has completed. | ||
| 7890 | @param[in,out] file File on which a write was completed */ | ||
| 7891 | 17881877 | void Fil_shard::write_completed(fil_node_t *file) { | |
| 7892 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17881881 times.
|
17881877 | ut_ad(mutex_owned()); |
| 7893 | |||
| 7894 | 17881881 | ++m_modification_counter; | |
| 7895 | |||
| 7896 | 17881881 | file->modification_counter = m_modification_counter; | |
| 7897 | |||
| 7898 |
2/2✓ Branch 0 taken 1874989 times.
✓ Branch 1 taken 16006844 times.
|
17881881 | if (fil_disable_space_flushing(file->space)) { |
| 7899 | /* We don't need to keep track of not flushed changes as either: | ||
| 7900 | - user has explicitly disabled buffering, | ||
| 7901 | - or it is FIL_TYPE_TEMPORARY space and we don't ever flush these. */ | ||
| 7902 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1874988 times.
|
1874989 | ut_ad(!file->space->is_in_unflushed_spaces); |
| 7903 | |||
| 7904 | 1874988 | file->set_flushed(); | |
| 7905 | |||
| 7906 | } else { | ||
| 7907 | 16006844 | add_to_unflushed_list(file->space); | |
| 7908 | } | ||
| 7909 | 17882045 | } | |
| 7910 | |||
| 7911 | /** Updates the data structures when an I/O operation finishes. Updates the | ||
| 7912 | pending I/O's field in the file appropriately. | ||
| 7913 | @param[in] file Tablespace file | ||
| 7914 | @param[in] type Marks the file as modified type == WRITE */ | ||
| 7915 | 63920394 | void Fil_shard::complete_io(fil_node_t *file, const IORequest &type) { | |
| 7916 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63920375 times.
|
63920394 | ut_ad(mutex_owned()); |
| 7917 | |||
| 7918 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63920259 times.
|
63920375 | ut_a(file->n_pending_ios > 0); |
| 7919 | |||
| 7920 | 63920259 | --file->n_pending_ios; | |
| 7921 | |||
| 7922 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63920143 times.
|
63920259 | ut_ad(type.validate()); |
| 7923 | |||
| 7924 |
2/2✓ Branch 0 taken 17881914 times.
✓ Branch 1 taken 46038321 times.
|
63920143 | if (type.is_write()) { |
| 7925 |
4/6✓ Branch 0 taken 5774 times.
✓ Branch 1 taken 17876140 times.
✓ Branch 2 taken 5774 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 17881894 times.
|
17881914 | ut_ad(!srv_read_only_mode || fsp_is_system_temporary(file->space->id)); |
| 7926 | |||
| 7927 | 17881894 | write_completed(file); | |
| 7928 | } | ||
| 7929 | |||
| 7930 |
2/2✓ Branch 0 taken 56953359 times.
✓ Branch 1 taken 6967009 times.
|
63920368 | if (file->n_pending_ios == 0) { |
| 7931 | /* The file must be put back to the LRU list */ | ||
| 7932 | 56953359 | add_to_lru_if_needed(file); | |
| 7933 | } | ||
| 7934 | 63920410 | } | |
| 7935 | |||
| 7936 | /** Report information about an invalid page access. | ||
| 7937 | @param[in] block_offset Block offset | ||
| 7938 | @param[in] space_id Tablespace ID | ||
| 7939 | @param[in] space_name Tablespace name | ||
| 7940 | @param[in] byte_offset Byte offset | ||
| 7941 | @param[in] len I/O length | ||
| 7942 | @param[in] is_read I/O type | ||
| 7943 | @param[in] line Line called from */ | ||
| 7944 | ✗ | static void fil_report_invalid_page_access_low(page_no_t block_offset, | |
| 7945 | space_id_t space_id, | ||
| 7946 | const char *space_name, | ||
| 7947 | ulint byte_offset, ulint len, | ||
| 7948 | bool is_read, int line) { | ||
| 7949 | ✗ | ib::error(ER_IB_MSG_328) | |
| 7950 | ✗ | << "Trying to access page number " << block_offset | |
| 7951 | << " in" | ||
| 7952 | ✗ | " space " | |
| 7953 | ✗ | << space_id << ", space name " << space_name | |
| 7954 | << "," | ||
| 7955 | ✗ | " which is outside the tablespace bounds. Byte offset " | |
| 7956 | ✗ | << byte_offset << ", len " << len << ", i/o type " | |
| 7957 | ✗ | << (is_read ? "read" : "write") | |
| 7958 | << ". If you get this error at mysqld startup, please check" | ||
| 7959 | " that your my.cnf matches the ibdata files that you have in" | ||
| 7960 | ✗ | " the MySQL server."; | |
| 7961 | |||
| 7962 | ✗ | ib::error(ER_IB_MSG_329) << "Server exits" | |
| 7963 | #ifdef UNIV_DEBUG | ||
| 7964 | ✗ | << " at " | |
| 7965 | ✗ | << "fil0fil.cc" | |
| 7966 | ✗ | << "[" << line << "]" | |
| 7967 | #endif /* UNIV_DEBUG */ | ||
| 7968 | ✗ | << "."; | |
| 7969 | |||
| 7970 | ✗ | ut_error; | |
| 7971 | } | ||
| 7972 | |||
| 7973 | #define fil_report_invalid_page_access(b, s, n, o, l, t) \ | ||
| 7974 | fil_report_invalid_page_access_low((b), (s), (n), (o), (l), (t), __LINE__) | ||
| 7975 | |||
| 7976 | /** Set encryption information for IORequest. | ||
| 7977 | @param[in,out] req_type IO request | ||
| 7978 | @param[in] page_id page id | ||
| 7979 | @param[in] space table space */ | ||
| 7980 | 63613788 | void fil_io_set_encryption(IORequest &req_type, const page_id_t &page_id, | |
| 7981 | fil_space_t *space) { | ||
| 7982 | // TODO: now that dblwr doesn't exist in sys , should we encrypt all pages? | ||
| 7983 | // Or is there performance impact by encrypting TRX_SYS_PAGE which is | ||
| 7984 | // modified on every trx commit (binlog position is written) | ||
| 7985 | |||
| 7986 | /* Don't encrypt pages of system tablespace upto TRX_SYS_PAGE(including). The | ||
| 7987 | doublewrite buffer header is on TRX_SYS_PAGE */ | ||
| 7988 |
8/8✓ Branch 0 taken 1141000 times.
✓ Branch 1 taken 62472860 times.
✓ Branch 2 taken 1140790 times.
✓ Branch 3 taken 210 times.
✓ Branch 4 taken 952794 times.
✓ Branch 5 taken 187996 times.
✓ Branch 6 taken 952794 times.
✓ Branch 7 taken 62661066 times.
|
64754578 | if (fsp_is_system_tablespace(space->id) && space->crypt_data == nullptr && |
| 7989 | 1140790 | page_id.page_no() <= FSP_TRX_SYS_PAGE_NO) { | |
| 7990 | 952794 | req_type.clear_encrypted(); | |
| 7991 | 952794 | return; | |
| 7992 | } | ||
| 7993 | |||
| 7994 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 62661037 times.
|
62661066 | ut_a(!req_type.is_log()); |
| 7995 | /* Don't encrypt page 0 of all tablespaces except redo log | ||
| 7996 | tablespace, all pages from the system tablespace. */ | ||
| 7997 |
2/2✓ Branch 0 taken 53647 times.
✓ Branch 1 taken 27194 times.
|
80841 | if ((space->encryption_op_in_progress == Encryption::Progress::DECRYPTION && |
| 7998 | 80841 | req_type.is_write()) || | |
| 7999 |
8/8✓ Branch 0 taken 80841 times.
✓ Branch 1 taken 62580196 times.
✓ Branch 2 taken 1073730 times.
✓ Branch 3 taken 61560142 times.
✓ Branch 4 taken 6748 times.
✓ Branch 5 taken 1066982 times.
✓ Branch 6 taken 61594117 times.
✓ Branch 7 taken 1066949 times.
|
62741878 | !space->can_encrypt() || page_id.page_no() == 0) { |
| 8000 | 61594117 | req_type.clear_encrypted(); | |
| 8001 | 61594113 | return; | |
| 8002 | } | ||
| 8003 | |||
| 8004 | /* For writing temporary tablespace, if encryption for temporary | ||
| 8005 | tablespace is disabled, skip setting encryption. | ||
| 8006 | Encryption of session temporary tablespaces is independent of | ||
| 8007 | innodb_temp_tablespace_encrypt */ | ||
| 8008 |
8/8✓ Branch 0 taken 2342 times.
✓ Branch 1 taken 1064640 times.
✓ Branch 2 taken 156 times.
✓ Branch 3 taken 2186 times.
✓ Branch 4 taken 38 times.
✓ Branch 5 taken 118 times.
✓ Branch 6 taken 38 times.
✓ Branch 7 taken 1066944 times.
|
1067105 | if (fsp_is_global_temporary(space->id) && !srv_tmp_tablespace_encrypt && |
| 8009 | 156 | req_type.is_write()) { | |
| 8010 | 38 | req_type.clear_encrypted(); | |
| 8011 | 38 | return; | |
| 8012 | } | ||
| 8013 | |||
| 8014 | /* For writing undo log, if encryption for undo log is disabled, | ||
| 8015 | skip set encryption. */ | ||
| 8016 |
8/8✓ Branch 0 taken 764791 times.
✓ Branch 1 taken 302153 times.
✓ Branch 2 taken 80125 times.
✓ Branch 3 taken 684666 times.
✓ Branch 4 taken 6550 times.
✓ Branch 5 taken 73575 times.
✓ Branch 6 taken 6550 times.
✓ Branch 7 taken 1060394 times.
|
1147069 | if (fsp_is_undo_tablespace(space->id) && !srv_undo_log_encrypt && |
| 8017 | 80125 | req_type.is_write()) { | |
| 8018 | 6550 | req_type.clear_encrypted(); | |
| 8019 | 6550 | return; | |
| 8020 | } | ||
| 8021 | |||
| 8022 |
2/2✓ Branch 0 taken 428784 times.
✓ Branch 1 taken 631610 times.
|
1060394 | if (req_type.get_encrypted_block() != nullptr) { |
| 8023 | /* Already encrypted. */ | ||
| 8024 | 428784 | req_type.clear_encrypted(); | |
| 8025 | 428786 | return; | |
| 8026 | } | ||
| 8027 | |||
| 8028 | 631610 | req_type.encryption_key(space->m_encryption_metadata.m_key, | |
| 8029 | space->m_encryption_metadata.m_key_len, | ||
| 8030 | 631610 | space->m_encryption_metadata.m_iv); | |
| 8031 | |||
| 8032 | 631610 | req_type.encryption_algorithm(Encryption::AES); | |
| 8033 | } | ||
| 8034 | |||
| 8035 | 63613635 | AIO_mode Fil_shard::get_AIO_mode(const IORequest &, bool sync) { | |
| 8036 | #ifndef UNIV_HOTBACKUP | ||
| 8037 |
2/2✓ Branch 0 taken 45215294 times.
✓ Branch 1 taken 18398341 times.
|
63613635 | if (sync) { |
| 8038 | 45215294 | return AIO_mode::SYNC; | |
| 8039 | |||
| 8040 | } else { | ||
| 8041 | 18398341 | return AIO_mode::NORMAL; | |
| 8042 | } | ||
| 8043 | #else /* !UNIV_HOTBACKUP */ | ||
| 8044 | ut_a(sync); | ||
| 8045 | return AIO_mode::SYNC; | ||
| 8046 | #endif /* !UNIV_HOTBACKUP */ | ||
| 8047 | } | ||
| 8048 | |||
| 8049 | 63613808 | dberr_t Fil_shard::get_file_for_io(fil_space_t *space, page_no_t *page_no, | |
| 8050 | fil_node_t *&file) { | ||
| 8051 | 63613808 | file = space->get_file_node(page_no); | |
| 8052 |
2/2✓ Branch 0 taken 959 times.
✓ Branch 1 taken 63613415 times.
|
63614374 | return (file == nullptr) ? DB_ERROR : DB_SUCCESS; |
| 8053 | } | ||
| 8054 | |||
| 8055 | 63613891 | dberr_t Fil_shard::do_io(const IORequest &type, bool sync, | |
| 8056 | const page_id_t &page_id, const page_size_t &page_size, | ||
| 8057 | ulint byte_offset, ulint len, void *buf, void *message, | ||
| 8058 | trx_t *trx, bool should_buffer) { | ||
| 8059 | 63613891 | IORequest req_type(type); | |
| 8060 | |||
| 8061 |
2/4✓ Branch 0 taken 63615285 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 63615087 times.
|
63614383 | ut_ad(req_type.validate()); |
| 8062 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63614654 times.
|
63615087 | ut_ad(!req_type.is_log()); |
| 8063 | |||
| 8064 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63614302 times.
|
63614654 | ut_ad(len > 0); |
| 8065 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63613703 times.
|
63614302 | ut_ad(byte_offset < UNIV_PAGE_SIZE); |
| 8066 |
4/6✓ Branch 0 taken 73208 times.
✓ Branch 1 taken 63540709 times.
✓ Branch 2 taken 73208 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 63613660 times.
|
63613703 | ut_ad(!page_size.is_compressed() || byte_offset == 0); |
| 8067 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63613805 times.
|
63613660 | ut_ad(UNIV_PAGE_SIZE == (ulong)(1 << UNIV_PAGE_SIZE_SHIFT)); |
| 8068 | |||
| 8069 |
2/4✓ Branch 0 taken 63613525 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 63613525 times.
|
63613805 | ut_ad(fil_validate_skip()); |
| 8070 | |||
| 8071 | #ifndef UNIV_HOTBACKUP | ||
| 8072 | /* ibuf bitmap pages must be read in the sync AIO mode: */ | ||
| 8073 |
9/12✓ Branch 0 taken 63528205 times.
✓ Branch 1 taken 85320 times.
✓ Branch 2 taken 45954137 times.
✓ Branch 3 taken 17574291 times.
✓ Branch 4 taken 45954237 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 93355 times.
✓ Branch 7 taken 45860882 times.
✓ Branch 8 taken 93355 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 63613935 times.
|
63613525 | ut_ad(recv_no_ibuf_operations || req_type.is_write() || |
| 8074 | !ibuf_bitmap_page(page_id, page_size) || sync); | ||
| 8075 | |||
| 8076 |
1/2✓ Branch 0 taken 63613962 times.
✗ Branch 1 not taken.
|
63613935 | auto aio_mode = get_AIO_mode(req_type, sync); |
| 8077 | |||
| 8078 |
2/2✓ Branch 0 taken 46006854 times.
✓ Branch 1 taken 17607199 times.
|
63613962 | if (req_type.is_read()) { |
| 8079 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46006881 times.
|
46006854 | ut_ad(type.get_original_size() == 0); |
| 8080 |
1/2✓ Branch 0 taken 46006859 times.
✗ Branch 1 not taken.
|
46006881 | srv_stats.data_read.add(len); |
| 8081 | |||
| 8082 |
6/6✓ Branch 0 taken 941443 times.
✓ Branch 1 taken 45065416 times.
✓ Branch 2 taken 889547 times.
✓ Branch 3 taken 51896 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 46006857 times.
|
46896405 | if (aio_mode == AIO_mode::NORMAL && !recv_no_ibuf_operations && |
| 8083 |
3/4✓ Branch 0 taken 889546 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 889545 times.
|
889547 | ibuf_page(page_id, page_size, UT_LOCATION_HERE, nullptr)) { |
| 8084 | /* Reduce probability of deadlock bugs | ||
| 8085 | in connection with ibuf: do not let the | ||
| 8086 | ibuf I/O handler sleep */ | ||
| 8087 | |||
| 8088 | 1 | req_type.clear_do_not_wake(); | |
| 8089 | |||
| 8090 | 1 | aio_mode = AIO_mode::IBUF; | |
| 8091 | } | ||
| 8092 | |||
| 8093 | #ifdef UNIV_DEBUG | ||
| 8094 |
1/2✓ Branch 0 taken 46006982 times.
✗ Branch 1 not taken.
|
46006858 | mutex_acquire(); |
| 8095 | /* Should never attempt to read from a deleted tablespace, unless we | ||
| 8096 | are also importing the tablespace. By the time we get here in the final | ||
| 8097 | phase of import the state has changed. Therefore we check if there is | ||
| 8098 | an active fil_space_t instance with the same ID. */ | ||
| 8099 |
2/2✓ Branch 0 taken 363256 times.
✓ Branch 1 taken 46006977 times.
|
46370238 | for (auto pair : m_deleted_spaces) { |
| 8100 |
2/2✓ Branch 0 taken 3296 times.
✓ Branch 1 taken 359960 times.
|
363256 | if (pair.first == page_id.space()) { |
| 8101 |
1/2✓ Branch 0 taken 3296 times.
✗ Branch 1 not taken.
|
3296 | auto space = get_space_by_id(page_id.space()); |
| 8102 |
1/2✓ Branch 0 taken 3296 times.
✗ Branch 1 not taken.
|
3296 | if (space != nullptr) { |
| 8103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3296 times.
|
3296 | ut_a(pair.second != space); |
| 8104 | } | ||
| 8105 | } | ||
| 8106 | } | ||
| 8107 |
1/2✓ Branch 0 taken 46006981 times.
✗ Branch 1 not taken.
|
46006977 | mutex_release(); |
| 8108 | #endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */ | ||
| 8109 | |||
| 8110 |
1/2✓ Branch 0 taken 17607059 times.
✗ Branch 1 not taken.
|
17607199 | } else if (req_type.is_write()) { |
| 8111 |
5/8✓ Branch 0 taken 5735 times.
✓ Branch 1 taken 17601324 times.
✓ Branch 2 taken 5841 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5841 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 17607032 times.
|
17607059 | ut_ad(!srv_read_only_mode || fsp_is_system_temporary(page_id.space())); |
| 8112 | |||
| 8113 |
1/2✓ Branch 0 taken 17606504 times.
✗ Branch 1 not taken.
|
17607032 | srv_stats.data_written.add(len); |
| 8114 | } | ||
| 8115 | #else /* !UNIV_HOTBACKUP */ | ||
| 8116 | ut_a(sync); | ||
| 8117 | auto aio_mode = AIO_mode::SYNC; | ||
| 8118 | #endif /* !UNIV_HOTBACKUP */ | ||
| 8119 | |||
| 8120 | /* Reserve the mutex and make sure that we can open at | ||
| 8121 | least one file while holding it, if the file is not already open */ | ||
| 8122 | |||
| 8123 | 63613364 | auto bpage = static_cast<buf_page_t *>(message); | |
| 8124 | |||
| 8125 |
1/2✓ Branch 0 taken 63615736 times.
✗ Branch 1 not taken.
|
63613364 | mutex_acquire(); |
| 8126 |
1/2✓ Branch 0 taken 63615554 times.
✗ Branch 1 not taken.
|
63615736 | auto space = get_space_by_id(page_id.space()); |
| 8127 | |||
| 8128 | /* If we are deleting a tablespace we don't allow async read | ||
| 8129 | operations on that. However, we do allow write operations and | ||
| 8130 | sync read operations. */ | ||
| 8131 |
6/6✓ Branch 0 taken 63614197 times.
✓ Branch 1 taken 1357 times.
✓ Branch 2 taken 46006978 times.
✓ Branch 3 taken 17607301 times.
✓ Branch 4 taken 1355 times.
✓ Branch 5 taken 63614281 times.
|
173236811 | if (space == nullptr || |
| 8132 |
3/4✓ Branch 0 taken 941443 times.
✓ Branch 1 taken 45065535 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 941445 times.
|
109621175 | (req_type.is_read() && !sync && space->stop_new_ops)) { |
| 8133 | #ifndef UNIV_HOTBACKUP | ||
| 8134 |
3/6✓ Branch 0 taken 1355 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1355 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1355 times.
✗ Branch 5 not taken.
|
1355 | const auto is_page_stale = bpage != nullptr && bpage->is_stale(); |
| 8135 | #endif /* !UNIV_HOTBACKUP */ | ||
| 8136 | |||
| 8137 |
1/2✓ Branch 0 taken 1355 times.
✗ Branch 1 not taken.
|
1355 | mutex_release(); |
| 8138 | |||
| 8139 |
1/2✓ Branch 0 taken 1355 times.
✗ Branch 1 not taken.
|
1355 | if (space == nullptr) { |
| 8140 | #ifndef UNIV_HOTBACKUP | ||
| 8141 |
3/6✓ Branch 0 taken 1355 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1355 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1355 times.
✗ Branch 5 not taken.
|
1355 | if (req_type.is_write() && is_page_stale) { |
| 8142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1355 times.
|
1355 | ut_a(bpage->get_space()->id == page_id.space()); |
| 8143 | 1355 | return DB_PAGE_IS_STALE; | |
| 8144 | } | ||
| 8145 | #endif /* !UNIV_HOTBACKUP */ | ||
| 8146 | |||
| 8147 | ✗ | if (!req_type.ignore_missing()) { | |
| 8148 | #ifndef UNIV_HOTBACKUP | ||
| 8149 | /* Don't have any record of this tablespace. print a warning. */ | ||
| 8150 | ✗ | if (!Fil_shard::is_deleted(page_id.space())) { | |
| 8151 | #endif /* !UNIV_HOTBACKUP */ | ||
| 8152 | ✗ | if (space == nullptr) { | |
| 8153 | ✗ | ib::error(ER_IB_MSG_330) | |
| 8154 | ✗ | << "Trying to do I/O on a tablespace" | |
| 8155 | ✗ | << " which does not exist. I/O type: " | |
| 8156 | ✗ | << (req_type.is_read() ? "read" : "write") | |
| 8157 | ✗ | << ", page: " << page_id << ", I/O length: " << len << " bytes"; | |
| 8158 | } else { | ||
| 8159 | ✗ | ib::error(ER_IB_MSG_331) | |
| 8160 | ✗ | << "Trying to do async read on a tablespace which is being" | |
| 8161 | ✗ | << " deleted. Tablespace name: \"" << space->name << "\"," | |
| 8162 | ✗ | << " page: " << page_id << ", read length: " << len << " bytes"; | |
| 8163 | } | ||
| 8164 | #ifndef UNIV_HOTBACKUP | ||
| 8165 | } | ||
| 8166 | #endif /* !UNIV_HOTBACKUP */ | ||
| 8167 | } | ||
| 8168 | } | ||
| 8169 | |||
| 8170 | ✗ | return DB_TABLESPACE_DELETED; | |
| 8171 | } | ||
| 8172 | |||
| 8173 | #ifndef UNIV_HOTBACKUP | ||
| 8174 |
2/2✓ Branch 0 taken 62806649 times.
✓ Branch 1 taken 807632 times.
|
63614281 | if (bpage != nullptr) { |
| 8175 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 62807057 times.
|
62806649 | ut_a(bpage->get_space()->id == page_id.space()); |
| 8176 | |||
| 8177 |
7/8✓ Branch 0 taken 17598663 times.
✓ Branch 1 taken 45208468 times.
✓ Branch 2 taken 17598704 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 17598680 times.
✓ Branch 6 taken 24 times.
✓ Branch 7 taken 62807148 times.
|
62807057 | if (req_type.is_write() && bpage->is_stale()) { |
| 8178 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | mutex_release(); |
| 8179 | 24 | return DB_PAGE_IS_STALE; | |
| 8180 | } | ||
| 8181 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 62807061 times.
|
62807148 | ut_a(bpage->get_space() == space); |
| 8182 | } | ||
| 8183 | #endif /* !UNIV_HOTBACKUP */ | ||
| 8184 | |||
| 8185 | fil_node_t *file; | ||
| 8186 | 63614693 | auto page_no = page_id.page_no(); | |
| 8187 |
1/2✓ Branch 0 taken 63614381 times.
✗ Branch 1 not taken.
|
63613755 | auto err = get_file_for_io(space, &page_no, file); |
| 8188 | |||
| 8189 |
2/2✓ Branch 0 taken 959 times.
✓ Branch 1 taken 63613422 times.
|
63614381 | if (file == nullptr) { |
| 8190 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 959 times.
|
959 | ut_ad(err == DB_ERROR); |
| 8191 | |||
| 8192 |
1/2✓ Branch 0 taken 959 times.
✗ Branch 1 not taken.
|
959 | if (req_type.ignore_missing()) { |
| 8193 |
1/2✓ Branch 0 taken 959 times.
✗ Branch 1 not taken.
|
959 | mutex_release(); |
| 8194 | |||
| 8195 | 959 | return DB_ERROR; | |
| 8196 | } | ||
| 8197 | |||
| 8198 | #ifndef UNIV_HOTBACKUP | ||
| 8199 | ✗ | if (req_type.is_write() && bpage != nullptr && bpage->is_stale()) { | |
| 8200 | ✗ | ut_a(bpage->get_space()->id == page_id.space()); | |
| 8201 | |||
| 8202 | ✗ | mutex_release(); | |
| 8203 | ✗ | return DB_PAGE_IS_STALE; | |
| 8204 | } | ||
| 8205 | #endif /* !UNIV_HOTBACKUP */ | ||
| 8206 | |||
| 8207 | /* This is a hard error. */ | ||
| 8208 | ✗ | fil_report_invalid_page_access(page_id.page_no(), page_id.space(), | |
| 8209 | space->name, byte_offset, len, | ||
| 8210 | req_type.is_read()); | ||
| 8211 | } | ||
| 8212 | |||
| 8213 | #ifndef UNIV_HOTBACKUP | ||
| 8214 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 63613179 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 63613179 times.
|
63613179 | if (UNIV_UNLIKELY(space->is_corrupt && srv_pass_corrupt_table)) { |
| 8215 | /* should ignore i/o for the crashed space */ | ||
| 8216 | ✗ | if (srv_pass_corrupt_table == 1 || req_type.is_write()) { | |
| 8217 | ✗ | complete_io(file, type); | |
| 8218 | ✗ | if (aio_mode == AIO_mode::NORMAL) { | |
| 8219 | ✗ | ut_a(space->purpose == FIL_TYPE_TABLESPACE); | |
| 8220 | ✗ | buf_page_io_complete(static_cast<buf_page_t *>(message), false); | |
| 8221 | } | ||
| 8222 | } | ||
| 8223 | |||
| 8224 | ✗ | if (srv_pass_corrupt_table == 1 && req_type.is_read()) | |
| 8225 | ✗ | return (DB_TABLESPACE_DELETED); | |
| 8226 | ✗ | else if (req_type.is_write()) | |
| 8227 | ✗ | return (DB_SUCCESS); | |
| 8228 | } | ||
| 8229 | #endif | ||
| 8230 | |||
| 8231 |
2/4✓ Branch 0 taken 63613363 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 63613363 times.
|
63613179 | if (!prepare_file_for_io(file)) { |
| 8232 | #ifndef UNIV_HOTBACKUP | ||
| 8233 | ✗ | if (space->is_deleted()) { | |
| 8234 | ✗ | mutex_release(); | |
| 8235 | |||
| 8236 | ✗ | if (!sync) { | |
| 8237 | ✗ | ut_d(bpage->take_io_responsibility()); | |
| 8238 | ✗ | buf_page_io_complete(bpage, false); | |
| 8239 | } | ||
| 8240 | |||
| 8241 | ✗ | return DB_TABLESPACE_DELETED; | |
| 8242 | } | ||
| 8243 | #endif /* !UNIV_HOTBACKUP */ | ||
| 8244 | |||
| 8245 | ✗ | if (fsp_is_ibd_tablespace(space->id)) { | |
| 8246 | ✗ | mutex_release(); | |
| 8247 | |||
| 8248 | ✗ | if (!req_type.ignore_missing()) { | |
| 8249 | ✗ | ib::error(ER_IB_MSG_332) | |
| 8250 | << "Trying to do I/O to a tablespace" | ||
| 8251 | ✗ | " which exists without an .ibd data" | |
| 8252 | ✗ | << " file. I/O type: " << (req_type.is_read() ? "read" : "write") | |
| 8253 | ✗ | << ", page: " << page_id_t(page_id.space(), page_no) | |
| 8254 | ✗ | << ", I/O length: " << len << " bytes"; | |
| 8255 | } | ||
| 8256 | |||
| 8257 | ✗ | return DB_TABLESPACE_DELETED; | |
| 8258 | } | ||
| 8259 | |||
| 8260 | /* Could not open a file to perform IO and this is not a IBD file, | ||
| 8261 | which could have become deleted meanwhile. This is a fatal error. | ||
| 8262 | Note: any log information should be emitted inside prepare_file_for_io() | ||
| 8263 | called few lines earlier. That's because the specific reason for this | ||
| 8264 | problem is known only inside there. */ | ||
| 8265 | ✗ | ut_error; | |
| 8266 | } | ||
| 8267 | |||
| 8268 | /* Check that at least the start offset is within the bounds of a | ||
| 8269 | single-table tablespace, including rollback tablespaces. */ | ||
| 8270 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 63613361 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
63613363 | if (file->size <= page_no && space->id != TRX_SYS_SPACE) { |
| 8271 | #ifndef UNIV_HOTBACKUP | ||
| 8272 |
2/10✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
|
2 | if (req_type.is_write() && bpage != nullptr && bpage->is_stale()) { |
| 8273 | ✗ | ut_a(bpage->get_space()->id == page_id.space()); | |
| 8274 | ✗ | return DB_PAGE_IS_STALE; | |
| 8275 | } | ||
| 8276 | #endif /* !UNIV_HOTBACKUP */ | ||
| 8277 | |||
| 8278 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (req_type.ignore_missing()) { |
| 8279 | /* If we can tolerate the non-existent pages, we | ||
| 8280 | should return with DB_ERROR and let caller decide | ||
| 8281 | what to do. */ | ||
| 8282 | |||
| 8283 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | complete_io(file, req_type); |
| 8284 | |||
| 8285 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | mutex_release(); |
| 8286 | |||
| 8287 | 2 | return DB_ERROR; | |
| 8288 | } | ||
| 8289 | |||
| 8290 | /* This is a hard error. */ | ||
| 8291 | ✗ | fil_report_invalid_page_access(page_id.page_no(), page_id.space(), | |
| 8292 | space->name, byte_offset, len, | ||
| 8293 | req_type.is_read()); | ||
| 8294 | } | ||
| 8295 | |||
| 8296 |
1/2✓ Branch 0 taken 63613346 times.
✗ Branch 1 not taken.
|
63613361 | mutex_release(); |
| 8297 | |||
| 8298 |
3/4✓ Branch 0 taken 61991867 times.
✓ Branch 1 taken 1621479 times.
✓ Branch 2 taken 61992407 times.
✗ Branch 3 not taken.
|
63613346 | DEBUG_SYNC_C("innodb_fil_do_io_prepared_io_with_no_mutex"); |
| 8299 | |||
| 8300 |
6/10✓ Branch 0 taken 63540897 times.
✓ Branch 1 taken 73208 times.
✓ Branch 2 taken 63540887 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 63540796 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 63540796 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 63613897 times.
|
63613886 | ut_a(page_size.is_compressed() || |
| 8301 | page_size.physical() == page_size.logical()); | ||
| 8302 | |||
| 8303 |
1/2✓ Branch 0 taken 63613835 times.
✗ Branch 1 not taken.
|
63613897 | auto offset = (os_offset_t)page_no * page_size.physical(); |
| 8304 | |||
| 8305 | 63613835 | offset += byte_offset; | |
| 8306 | |||
| 8307 |
3/6✓ Branch 0 taken 63613759 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 63613752 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 63613755 times.
|
63613835 | ut_a(file->size - page_no >= |
| 8308 | (byte_offset + | ||
| 8309 | std::max(static_cast<uint32_t>(len), type.get_original_size()) + | ||
| 8310 | (page_size.physical() - 1)) / | ||
| 8311 | page_size.physical()); | ||
| 8312 | |||
| 8313 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63613582 times.
|
63613755 | ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0); |
| 8314 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63613706 times.
|
63613582 | ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0); |
| 8315 | |||
| 8316 | /* Don't compress the log, page 0 of all tablespaces, tables compressed with | ||
| 8317 | the old compression scheme and all pages from the system tablespace. */ | ||
| 8318 |
4/4✓ Branch 0 taken 17562065 times.
✓ Branch 1 taken 45809 times.
✓ Branch 2 taken 17087549 times.
✓ Branch 3 taken 474531 times.
|
98783683 | if (req_type.is_write() && !page_size.is_compressed() && |
| 8319 |
6/8✓ Branch 0 taken 17607897 times.
✓ Branch 1 taken 46005811 times.
✓ Branch 2 taken 17087647 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17087650 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17087648 times.
✓ Branch 7 taken 46526150 times.
|
115871312 | page_id.page_no() > 0 && IORequest::is_punch_hole_supported() && |
| 8320 |
1/2✓ Branch 0 taken 17087652 times.
✗ Branch 1 not taken.
|
17087650 | file->punch_hole) { |
| 8321 |
1/2✓ Branch 0 taken 17087647 times.
✗ Branch 1 not taken.
|
17087648 | req_type.set_punch_hole(); |
| 8322 | |||
| 8323 |
1/2✓ Branch 0 taken 17087652 times.
✗ Branch 1 not taken.
|
17087647 | req_type.compression_algorithm(space->compression_type); |
| 8324 | |||
| 8325 | } else { | ||
| 8326 | 46526150 | req_type.clear_compressed(); | |
| 8327 | } | ||
| 8328 | |||
| 8329 |
2/2✓ Branch 0 taken 73193 times.
✓ Branch 1 taken 63540715 times.
|
63613923 | if (page_size.is_compressed()) { |
| 8330 | 73193 | req_type.mark_page_zip_compressed(); | |
| 8331 |
1/2✓ Branch 0 taken 73193 times.
✗ Branch 1 not taken.
|
73193 | req_type.set_zip_page_physical_size(page_size.physical()); |
| 8332 |
2/4✓ Branch 0 taken 73193 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 73193 times.
|
73193 | ut_ad(page_size.physical() > 0); |
| 8333 | } | ||
| 8334 | |||
| 8335 | /* Set encryption information. */ | ||
| 8336 |
1/2✓ Branch 0 taken 63613620 times.
✗ Branch 1 not taken.
|
63613908 | fil_io_set_encryption(req_type, page_id, space); |
| 8337 | |||
| 8338 | 63613620 | req_type.block_size(file->block_size); | |
| 8339 | |||
| 8340 | #ifdef UNIV_HOTBACKUP | ||
| 8341 | /* In mysqlbackup do normal I/O, not AIO */ | ||
| 8342 | if (req_type.is_read()) { | ||
| 8343 | err = os_file_read(req_type, file->name, file->handle, buf, offset, len); | ||
| 8344 | |||
| 8345 | } else { | ||
| 8346 | ut_ad(!srv_read_only_mode || fsp_is_system_temporary(page_id.space())); | ||
| 8347 | |||
| 8348 | err = os_file_write(req_type, file->name, file->handle, buf, offset, len); | ||
| 8349 | } | ||
| 8350 | #else /* UNIV_HOTBACKUP */ | ||
| 8351 | /* Queue the aio request */ | ||
| 8352 |
4/6✓ Branch 0 taken 63613715 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6904060 times.
✓ Branch 3 taken 56709655 times.
✓ Branch 4 taken 63613579 times.
✗ Branch 5 not taken.
|
63613879 | err = os_aio( |
| 8353 | req_type, aio_mode, file->name, file->handle, buf, offset, len, | ||
| 8354 | fsp_is_system_temporary(page_id.space()) ? false : srv_read_only_mode, | ||
| 8355 | file, message, page_id.space(), trx, should_buffer); | ||
| 8356 | |||
| 8357 | #endif /* UNIV_HOTBACKUP */ | ||
| 8358 | |||
| 8359 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63613579 times.
|
63613579 | if (err == DB_IO_NO_PUNCH_HOLE) { |
| 8360 | ✗ | err = DB_SUCCESS; | |
| 8361 | |||
| 8362 | ✗ | if (file->punch_hole) { | |
| 8363 | ✗ | ib::warn(ER_IB_MSG_333) << "Punch hole failed for '" << file->name << "'"; | |
| 8364 | } | ||
| 8365 | |||
| 8366 | ✗ | fil_no_punch_hole(file); | |
| 8367 | } | ||
| 8368 | |||
| 8369 | /* We an try to recover the page from the double write buffer if | ||
| 8370 | the decompression fails or the page is corrupt. */ | ||
| 8371 | |||
| 8372 |
4/8✓ Branch 0 taken 62823660 times.
✓ Branch 1 taken 789438 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 62823660 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 63613306 times.
|
63613579 | ut_a(req_type.is_dblwr() || err == DB_SUCCESS || err == DB_IO_DECRYPT_FAIL); |
| 8373 | |||
| 8374 |
2/2✓ Branch 0 taken 45213897 times.
✓ Branch 1 taken 18399409 times.
|
63613306 | if (sync) { |
| 8375 | /* The i/o operation is already completed when we return from | ||
| 8376 | os_aio: */ | ||
| 8377 | |||
| 8378 |
1/2✓ Branch 0 taken 45214410 times.
✗ Branch 1 not taken.
|
45213897 | mutex_acquire(); |
| 8379 | |||
| 8380 |
1/2✓ Branch 0 taken 45214422 times.
✗ Branch 1 not taken.
|
45214410 | complete_io(file, req_type); |
| 8381 | |||
| 8382 |
1/2✓ Branch 0 taken 45214436 times.
✗ Branch 1 not taken.
|
45214422 | mutex_release(); |
| 8383 | |||
| 8384 |
3/4✓ Branch 0 taken 45214426 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 45214342 times.
|
45214436 | ut_ad(fil_validate_skip()); |
| 8385 | } | ||
| 8386 | |||
| 8387 | 63613751 | return err; | |
| 8388 | 63616091 | } | |
| 8389 | |||
| 8390 | #ifndef UNIV_HOTBACKUP | ||
| 8391 | /** Waits for an AIO operation to complete. This function is used to write the | ||
| 8392 | handler for completed requests. The aio array of pending requests is divided | ||
| 8393 | into segments (see os0file.cc for more info). The thread specifies which | ||
| 8394 | segment it wants to wait for. | ||
| 8395 | @param[in] segment The number of the segment in the AIO array | ||
| 8396 | to wait for */ | ||
| 8397 | 19010182 | void fil_aio_wait(ulint segment) { | |
| 8398 | void *m2; | ||
| 8399 | fil_node_t *m1; | ||
| 8400 | 19010182 | IORequest type; | |
| 8401 | |||
| 8402 |
2/4✓ Branch 0 taken 19010548 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19010677 times.
|
19010737 | ut_ad(fil_validate_skip()); |
| 8403 | |||
| 8404 |
1/2✓ Branch 0 taken 18999558 times.
✗ Branch 1 not taken.
|
19010677 | auto err = os_aio_handler(segment, &m1, &m2, &type); |
| 8405 |
2/2✓ Branch 0 taken 63 times.
✓ Branch 1 taken 18999733 times.
|
18999558 | ut_a(err == DB_SUCCESS); |
| 8406 | |||
| 8407 | 18999733 | auto file = reinterpret_cast<fil_node_t *>(m1); | |
| 8408 | |||
| 8409 |
2/2✓ Branch 0 taken 600020 times.
✓ Branch 1 taken 18399713 times.
|
18999733 | if (file == nullptr) { |
| 8410 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 599998 times.
|
600020 | ut_ad(srv_shutdown_state.load() == SRV_SHUTDOWN_EXIT_THREADS); |
| 8411 | 599998 | return; | |
| 8412 | } | ||
| 8413 | |||
| 8414 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18399766 times.
|
18399713 | ut_a(!type.is_dblwr()); |
| 8415 | |||
| 8416 |
1/2✓ Branch 0 taken 18399710 times.
✗ Branch 1 not taken.
|
18399766 | srv_set_io_thread_op_info(segment, "complete io for file"); |
| 8417 | |||
| 8418 |
1/2✓ Branch 0 taken 18399756 times.
✗ Branch 1 not taken.
|
18399710 | auto shard = fil_system->shard_by_id(file->space->id); |
| 8419 | |||
| 8420 |
1/2✓ Branch 0 taken 18399698 times.
✗ Branch 1 not taken.
|
18399756 | shard->mutex_acquire(); |
| 8421 | |||
| 8422 |
1/2✓ Branch 0 taken 18399715 times.
✗ Branch 1 not taken.
|
18399698 | shard->complete_io(file, type); |
| 8423 | |||
| 8424 |
1/2✓ Branch 0 taken 18399740 times.
✗ Branch 1 not taken.
|
18399715 | shard->mutex_release(); |
| 8425 | |||
| 8426 |
3/4✓ Branch 0 taken 18399702 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 18399634 times.
|
18399740 | ut_ad(fil_validate_skip()); |
| 8427 | |||
| 8428 | /* Do the i/o handling */ | ||
| 8429 | /* IMPORTANT: since i/o handling for reads will read also the insert | ||
| 8430 | buffer in tablespace 0, you have to be very careful not to introduce | ||
| 8431 | deadlocks in the i/o system. We keep tablespace 0 data files always | ||
| 8432 | open, and use a special i/o thread to serve insert buffer requests. */ | ||
| 8433 | |||
| 8434 |
1/2✓ Branch 0 taken 18399634 times.
✗ Branch 1 not taken.
|
18399634 | switch (file->space->purpose) { |
| 8435 | 18399634 | case FIL_TYPE_IMPORT: | |
| 8436 | case FIL_TYPE_TEMPORARY: | ||
| 8437 | case FIL_TYPE_TABLESPACE: | ||
| 8438 |
1/2✓ Branch 0 taken 18399621 times.
✗ Branch 1 not taken.
|
18399634 | srv_set_io_thread_op_info(segment, "complete io for buf page"); |
| 8439 | |||
| 8440 | /* async single page writes from the dblwr buffer don't have | ||
| 8441 | access to the page */ | ||
| 8442 |
1/2✓ Branch 0 taken 18399628 times.
✗ Branch 1 not taken.
|
18399621 | if (m2 != nullptr) { |
| 8443 | 18399628 | auto bpage = static_cast<buf_page_t *>(m2); | |
| 8444 |
1/2✓ Branch 0 taken 18399375 times.
✗ Branch 1 not taken.
|
18399628 | ut_d(bpage->take_io_responsibility()); |
| 8445 |
1/2✓ Branch 0 taken 18398197 times.
✗ Branch 1 not taken.
|
18399375 | buf_page_io_complete(bpage, false); |
| 8446 | } | ||
| 8447 | 18398190 | return; | |
| 8448 | } | ||
| 8449 | |||
| 8450 | ✗ | ut_d(ut_error); | |
| 8451 | 18998188 | } | |
| 8452 | #endif /* !UNIV_HOTBACKUP */ | ||
| 8453 | |||
| 8454 | /** Read or write data from a file. | ||
| 8455 | @param[in] type IO context | ||
| 8456 | @param[in] sync If true then do synchronous IO | ||
| 8457 | @param[in] page_id page id | ||
| 8458 | @param[in] page_size page size | ||
| 8459 | @param[in] byte_offset remainder of offset in bytes; in aio this | ||
| 8460 | must be divisible by the OS block size | ||
| 8461 | @param[in] len how many bytes to read or write; this must | ||
| 8462 | not cross a file boundary; in AIO this must | ||
| 8463 | be a block size multiple | ||
| 8464 | @param[in,out] buf buffer where to store read data or from where | ||
| 8465 | to write; in AIO this must be appropriately | ||
| 8466 | aligned | ||
| 8467 | @param[in] message message for AIO handler if !sync, else ignored | ||
| 8468 | @param[in] should_buffer whether to buffer an aio request. AIO read | ||
| 8469 | ahead uses this. If you plan to use this | ||
| 8470 | parameter, make sure you remember to call | ||
| 8471 | os_aio_dispatch_read_array_submit() when you're | ||
| 8472 | ready to commit all your requests. | ||
| 8473 | @return error code | ||
| 8474 | @retval DB_SUCCESS on success | ||
| 8475 | @retval DB_TABLESPACE_DELETED if the tablespace does not exist */ | ||
| 8476 | 63613086 | dberr_t _fil_io(const IORequest &type, bool sync, const page_id_t &page_id, | |
| 8477 | const page_size_t &page_size, ulint byte_offset, ulint len, | ||
| 8478 | void *buf, void *message, trx_t *trx, bool should_buffer) { | ||
| 8479 | 63613086 | auto shard = fil_system->shard_by_id(page_id.space()); | |
| 8480 | #ifdef UNIV_DEBUG | ||
| 8481 |
2/2✓ Branch 0 taken 18399693 times.
✓ Branch 1 taken 45214229 times.
|
63613922 | if (!sync) { |
| 8482 | /* In case of async io we transfer the io responsibility to the thread which | ||
| 8483 | will perform the io completion routine. */ | ||
| 8484 | 18399693 | static_cast<buf_page_t *>(message)->release_io_responsibility(); | |
| 8485 | } | ||
| 8486 | #endif | ||
| 8487 | |||
| 8488 | 63613705 | auto const err = shard->do_io(type, sync, page_id, page_size, byte_offset, | |
| 8489 | len, buf, message, trx, should_buffer); | ||
| 8490 | #ifdef UNIV_DEBUG | ||
| 8491 | /* If the error prevented async io, then we haven't actually transfered the | ||
| 8492 | io responsibility at all, so we revert the debug io responsibility info. */ | ||
| 8493 | 63616045 | auto bpage = static_cast<buf_page_t *>(message); | |
| 8494 | |||
| 8495 | /* When space is deleted, we could have marked the io complete. */ | ||
| 8496 |
7/8✓ Branch 0 taken 2340 times.
✓ Branch 1 taken 63613705 times.
✓ Branch 2 taken 1379 times.
✓ Branch 3 taken 961 times.
✓ Branch 4 taken 1379 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1379 times.
✓ Branch 7 taken 63614666 times.
|
63616045 | if (err != DB_SUCCESS && !sync && bpage->was_io_fixed()) { |
| 8497 | 1379 | bpage->take_io_responsibility(); | |
| 8498 | } | ||
| 8499 | #endif | ||
| 8500 | 63616196 | return err; | |
| 8501 | } | ||
| 8502 | |||
| 8503 | /** If the tablespace is on the unflushed list and there are no pending | ||
| 8504 | flushes then remove from the unflushed list. | ||
| 8505 | @param[in,out] space Tablespace to remove */ | ||
| 8506 | 8550971 | void Fil_shard::remove_from_unflushed_list(fil_space_t *space) { | |
| 8507 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8553006 times.
|
8550971 | ut_ad(mutex_owned()); |
| 8508 | |||
| 8509 |
6/6✓ Branch 0 taken 8551348 times.
✓ Branch 1 taken 1658 times.
✓ Branch 2 taken 7557499 times.
✓ Branch 3 taken 992104 times.
✓ Branch 4 taken 7557499 times.
✓ Branch 5 taken 993762 times.
|
8553006 | if (space->is_in_unflushed_spaces && space_is_flushed(space)) { |
| 8510 | 7557499 | space->is_in_unflushed_spaces = false; | |
| 8511 | |||
| 8512 | 7557499 | UT_LIST_REMOVE(m_unflushed_spaces, space); | |
| 8513 | } | ||
| 8514 | 8552345 | } | |
| 8515 | |||
| 8516 | 9044196 | void Fil_shard::space_flush(space_id_t space_id) { | |
| 8517 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9044191 times.
|
9044196 | ut_ad(mutex_owned()); |
| 8518 | |||
| 8519 | 9044191 | fil_space_t *space = get_space_by_id(space_id); | |
| 8520 | |||
| 8521 |
4/4✓ Branch 0 taken 9044161 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 8953049 times.
✓ Branch 3 taken 91112 times.
|
9044175 | if (space == nullptr || space->purpose == FIL_TYPE_TEMPORARY || |
| 8522 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8953051 times.
|
8953049 | space->stop_new_ops) { |
| 8523 | 91124 | return; | |
| 8524 | } | ||
| 8525 | |||
| 8526 | 8953051 | const bool disable_flush = fil_disable_space_flushing(space); | |
| 8527 | |||
| 8528 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8953049 times.
|
8953049 | if (disable_flush) { |
| 8529 | /* No need to flush. User has explicitly disabled | ||
| 8530 | buffering. However, flush should be called if the file | ||
| 8531 | size changes to keep OÐ… metadata in sync. */ | ||
| 8532 | ✗ | ut_ad(!space->is_in_unflushed_spaces); | |
| 8533 | ✗ | ut_ad(space_is_flushed(space)); | |
| 8534 | |||
| 8535 | /* Flush only if the file size changes */ | ||
| 8536 | ✗ | bool no_flush = true; | |
| 8537 | ✗ | for (const auto &file : space->files) { | |
| 8538 | #ifdef UNIV_DEBUG | ||
| 8539 | ✗ | ut_ad(file.is_flushed()); | |
| 8540 | #endif /* UNIV_DEBUG */ | ||
| 8541 | ✗ | if (file.flush_size != file.size) { | |
| 8542 | /* Found at least one file whose size has changed */ | ||
| 8543 | ✗ | no_flush = false; | |
| 8544 | ✗ | break; | |
| 8545 | } | ||
| 8546 | } | ||
| 8547 | |||
| 8548 | ✗ | if (no_flush) { | |
| 8549 | /* Nothing to flush. Just return */ | ||
| 8550 | ✗ | return; | |
| 8551 | } | ||
| 8552 | } | ||
| 8553 | |||
| 8554 | /* Prevent dropping of the space while we are flushing */ | ||
| 8555 | 8953049 | ++space->n_pending_flushes; | |
| 8556 | |||
| 8557 |
2/2✓ Branch 0 taken 8955775 times.
✓ Branch 1 taken 8952012 times.
|
17907923 | for (auto &file : space->files) { |
| 8558 | 8955845 | int64_t old_mod_counter = file.modification_counter; | |
| 8559 | |||
| 8560 |
2/2✓ Branch 0 taken 314 times.
✓ Branch 1 taken 8955531 times.
|
8955845 | if (!file.is_open) { |
| 8561 | 314 | continue; | |
| 8562 | } | ||
| 8563 | |||
| 8564 | /* Skip flushing if the file size has not changed since | ||
| 8565 | last flush was done and the flush mode is O_DIRECT_NO_FSYNC */ | ||
| 8566 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 8955531 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
8955531 | if (disable_flush && (file.flush_size == file.size)) { |
| 8567 | ✗ | ut_ad(old_mod_counter <= file.flush_counter); | |
| 8568 | ✗ | continue; | |
| 8569 | } | ||
| 8570 | |||
| 8571 | /* If we are here and the flush mode is O_DIRECT_NO_FSYNC, then | ||
| 8572 | it means that the file size has changed and hence, it should be | ||
| 8573 | flushed, irrespective of the mod_counter and flush counter values, | ||
| 8574 | which are always same in case of O_DIRECT_NO_FSYNC to avoid flush | ||
| 8575 | on every write operation. | ||
| 8576 | For other flush modes, if the flush_counter is same or ahead of | ||
| 8577 | the mod_counter, skip the flush. */ | ||
| 8578 |
4/4✓ Branch 0 taken 8955524 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 9295 times.
✓ Branch 3 taken 8946229 times.
|
8955531 | if (!disable_flush && (old_mod_counter <= file.flush_counter)) { |
| 8579 | 9295 | continue; | |
| 8580 | } | ||
| 8581 | |||
| 8582 |
2/3✗ Branch 0 not taken.
✓ Branch 1 taken 8946233 times.
✓ Branch 2 taken 3 times.
|
8946236 | switch (space->purpose) { |
| 8583 | ✗ | case FIL_TYPE_TEMPORARY: | |
| 8584 | ✗ | ut_error; // we already checked for this | |
| 8585 | |||
| 8586 | 8946233 | case FIL_TYPE_TABLESPACE: | |
| 8587 | case FIL_TYPE_IMPORT: | ||
| 8588 | 8946233 | ++fil_n_pending_tablespace_flushes; | |
| 8589 | 8946233 | break; | |
| 8590 | } | ||
| 8591 | |||
| 8592 | 8946236 | bool skip_flush = is_fast_shutdown(); | |
| 8593 | #ifdef _WIN32 | ||
| 8594 | if (file.is_raw_disk) { | ||
| 8595 | skip_flush |= true; | ||
| 8596 | } | ||
| 8597 | #endif /* _WIN32 */ | ||
| 8598 | |||
| 8599 |
4/4✓ Branch 0 taken 598167 times.
✓ Branch 1 taken 8942938 times.
✓ Branch 2 taken 594882 times.
✓ Branch 3 taken 3285 times.
|
9541105 | while (file.n_pending_flushes > 0 && !skip_flush) { |
| 8600 | /* We want to avoid calling os_file_flush() on | ||
| 8601 | the file twice at the same time, because we do | ||
| 8602 | not know what bugs OS's may contain in file | ||
| 8603 | I/O */ | ||
| 8604 | |||
| 8605 |
1/2✓ Branch 0 taken 594882 times.
✗ Branch 1 not taken.
|
594882 | int64_t sig_count = os_event_reset(file.sync_event); |
| 8606 | |||
| 8607 |
1/2✓ Branch 0 taken 594882 times.
✗ Branch 1 not taken.
|
594882 | mutex_release(); |
| 8608 | |||
| 8609 |
1/2✓ Branch 0 taken 594862 times.
✗ Branch 1 not taken.
|
594882 | os_event_wait_low(file.sync_event, sig_count); |
| 8610 | |||
| 8611 |
1/2✓ Branch 0 taken 594882 times.
✗ Branch 1 not taken.
|
594862 | mutex_acquire(); |
| 8612 | |||
| 8613 |
2/2✓ Branch 0 taken 393443 times.
✓ Branch 1 taken 201439 times.
|
594882 | if (file.flush_counter >= old_mod_counter) { |
| 8614 | 393443 | skip_flush |= true; | |
| 8615 | } | ||
| 8616 | 594882 | skip_flush |= is_fast_shutdown(); | |
| 8617 | } | ||
| 8618 | |||
| 8619 |
2/2✓ Branch 0 taken 8552718 times.
✓ Branch 1 taken 393505 times.
|
8946223 | if (!skip_flush) { |
| 8620 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8552738 times.
|
8552718 | ut_a(file.is_open); |
| 8621 | 8552738 | ++file.n_pending_flushes; | |
| 8622 | |||
| 8623 |
1/2✓ Branch 0 taken 8552809 times.
✗ Branch 1 not taken.
|
8552738 | mutex_release(); |
| 8624 | |||
| 8625 |
1/2✓ Branch 0 taken 8549690 times.
✗ Branch 1 not taken.
|
8552809 | os_file_flush(file.handle); |
| 8626 | |||
| 8627 | 8549690 | file.flush_size = file.size; | |
| 8628 | |||
| 8629 |
1/2✓ Branch 0 taken 8550992 times.
✗ Branch 1 not taken.
|
8549690 | mutex_acquire(); |
| 8630 | |||
| 8631 |
1/2✓ Branch 0 taken 8551898 times.
✗ Branch 1 not taken.
|
8550992 | os_event_set(file.sync_event); |
| 8632 | |||
| 8633 | 8551898 | --file.n_pending_flushes; | |
| 8634 | } | ||
| 8635 | |||
| 8636 |
2/2✓ Branch 0 taken 8552078 times.
✓ Branch 1 taken 393325 times.
|
8945403 | if (file.flush_counter < old_mod_counter) { |
| 8637 | 8552078 | file.flush_counter = old_mod_counter; | |
| 8638 | |||
| 8639 |
1/2✓ Branch 0 taken 8551940 times.
✗ Branch 1 not taken.
|
8552078 | remove_from_unflushed_list(space); |
| 8640 | } | ||
| 8641 | |||
| 8642 |
1/3✗ Branch 0 not taken.
✓ Branch 1 taken 8945265 times.
✗ Branch 2 not taken.
|
8945265 | switch (space->purpose) { |
| 8643 | ✗ | case FIL_TYPE_TEMPORARY: | |
| 8644 | ✗ | ut_error; // we already checked for this | |
| 8645 | |||
| 8646 | 8945265 | case FIL_TYPE_TABLESPACE: | |
| 8647 | case FIL_TYPE_IMPORT: | ||
| 8648 | 8945265 | --fil_n_pending_tablespace_flushes; | |
| 8649 | 8945265 | continue; | |
| 8650 | } | ||
| 8651 | |||
| 8652 | ✗ | ut_d(ut_error); | |
| 8653 | } | ||
| 8654 | |||
| 8655 | 8952012 | --space->n_pending_flushes; | |
| 8656 | } | ||
| 8657 | |||
| 8658 | 147579 | void fil_flush(space_id_t space_id) { | |
| 8659 | 147579 | auto shard = fil_system->shard_by_id(space_id); | |
| 8660 | |||
| 8661 | 147579 | shard->mutex_acquire(); | |
| 8662 | |||
| 8663 | /* Note: Will release and reacquire the Fil_shard::mutex. */ | ||
| 8664 | 147579 | shard->space_flush(space_id); | |
| 8665 | |||
| 8666 | 147579 | shard->mutex_release(); | |
| 8667 | 147579 | } | |
| 8668 | |||
| 8669 | 381894026 | void Fil_shard::flush_file_spaces() { | |
| 8670 |
1/2✓ Branch 0 taken 381877338 times.
✗ Branch 1 not taken.
|
381894026 | Space_ids space_ids; |
| 8671 | |||
| 8672 |
1/2✓ Branch 0 taken 381911871 times.
✗ Branch 1 not taken.
|
381877338 | mutex_acquire(); |
| 8673 | |||
| 8674 |
6/10✓ Branch 0 taken 381909497 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 381872890 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8623680 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 390508299 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8623678 times.
✓ Branch 9 taken 381884621 times.
|
390535555 | for (auto space : m_unflushed_spaces) { |
| 8675 |
4/4✓ Branch 0 taken 8623630 times.
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 8622539 times.
✓ Branch 3 taken 1143 times.
|
17247310 | if ((to_int(space->purpose) & FIL_TYPE_TABLESPACE) && |
| 8676 |
2/2✓ Branch 0 taken 8622541 times.
✓ Branch 1 taken 1089 times.
|
8623630 | !space->stop_new_ops) { |
| 8677 |
1/2✓ Branch 0 taken 8622541 times.
✗ Branch 1 not taken.
|
8622539 | space_ids.push_back(space->id); |
| 8678 | } | ||
| 8679 | } | ||
| 8680 | |||
| 8681 |
1/2✓ Branch 0 taken 382030820 times.
✗ Branch 1 not taken.
|
381884621 | mutex_release(); |
| 8682 | |||
| 8683 | /* Flush the spaces. It will not hurt to call fil_flush() on | ||
| 8684 | a non-existing space id. */ | ||
| 8685 |
2/2✓ Branch 0 taken 8622537 times.
✓ Branch 1 taken 381927030 times.
|
390652651 | for (auto space_id : space_ids) { |
| 8686 |
1/2✓ Branch 0 taken 8622539 times.
✗ Branch 1 not taken.
|
8622547 | mutex_acquire(); |
| 8687 | |||
| 8688 |
1/2✓ Branch 0 taken 8620514 times.
✗ Branch 1 not taken.
|
8622539 | space_flush(space_id); |
| 8689 | |||
| 8690 |
1/2✓ Branch 0 taken 8621831 times.
✗ Branch 1 not taken.
|
8620514 | mutex_release(); |
| 8691 | } | ||
| 8692 | 381927030 | } | |
| 8693 | |||
| 8694 | 5618542 | void Fil_system::flush_file_spaces() { | |
| 8695 |
2/2✓ Branch 0 taken 381894600 times.
✓ Branch 1 taken 5613751 times.
|
387539837 | for (auto shard : m_shards) { |
| 8696 |
1/2✓ Branch 0 taken 381921295 times.
✗ Branch 1 not taken.
|
381893079 | shard->flush_file_spaces(); |
| 8697 | } | ||
| 8698 | 5613751 | } | |
| 8699 | |||
| 8700 | 5604553 | void fil_flush_file_spaces() { fil_system->flush_file_spaces(); } | |
| 8701 | |||
| 8702 | /** Returns true if file address is undefined. | ||
| 8703 | @param[in] addr File address to check | ||
| 8704 | @return true if undefined */ | ||
| 8705 | 19896509 | bool fil_addr_is_null(const fil_addr_t &addr) { | |
| 8706 | 19896509 | return (addr.page == FIL_NULL); | |
| 8707 | } | ||
| 8708 | |||
| 8709 | /** Get the predecessor of a file page. | ||
| 8710 | @param[in] page File page | ||
| 8711 | @return FIL_PAGE_PREV */ | ||
| 8712 | 10207500 | page_no_t fil_page_get_prev(const byte *page) { | |
| 8713 | 10207500 | return mach_read_from_4(page + FIL_PAGE_PREV); | |
| 8714 | } | ||
| 8715 | |||
| 8716 | /** Get the successor of a file page. | ||
| 8717 | @param[in] page File page | ||
| 8718 | @return FIL_PAGE_NEXT */ | ||
| 8719 | 10211405 | page_no_t fil_page_get_next(const byte *page) { | |
| 8720 | 10211405 | return mach_read_from_4(page + FIL_PAGE_NEXT); | |
| 8721 | } | ||
| 8722 | |||
| 8723 | /** Sets the file page type. | ||
| 8724 | @param[in,out] page File page | ||
| 8725 | @param[in] type File page type to set */ | ||
| 8726 | 3263753 | void fil_page_set_type(byte *page, ulint type) { | |
| 8727 | 3263753 | mach_write_to_2(page + FIL_PAGE_TYPE, type); | |
| 8728 | 3263753 | } | |
| 8729 | |||
| 8730 | /** Reset the page type. | ||
| 8731 | Data files created before MySQL 5.1 may contain garbage in FIL_PAGE_TYPE. | ||
| 8732 | In MySQL 3.23.53, only undo log pages and index pages were tagged. | ||
| 8733 | Any other pages were written with uninitialized bytes in FIL_PAGE_TYPE. | ||
| 8734 | @param[in] page_id Page number | ||
| 8735 | @param[in,out] page Page with invalid FIL_PAGE_TYPE | ||
| 8736 | @param[in] type Expected page type | ||
| 8737 | @param[in,out] mtr Mini-transaction */ | ||
| 8738 | 1 | void fil_page_reset_type(const page_id_t &page_id, byte *page, ulint type, | |
| 8739 | mtr_t *mtr) { | ||
| 8740 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | ib::info(ER_IB_MSG_334) << "Resetting invalid page " << page_id << " type " |
| 8741 |
5/10✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | << fil_page_get_type(page) << " to " << type << "."; |
| 8742 | 1 | mlog_write_ulint(page + FIL_PAGE_TYPE, type, MLOG_2BYTES, mtr); | |
| 8743 | 1 | } | |
| 8744 | |||
| 8745 | /** Closes the tablespace memory cache. */ | ||
| 8746 | 8379 | void fil_close() { | |
| 8747 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8379 times.
|
8379 | if (fil_system == nullptr) { |
| 8748 | ✗ | return; | |
| 8749 | } | ||
| 8750 | |||
| 8751 | 8379 | ut::delete_(fil_system); | |
| 8752 | |||
| 8753 | 8379 | fil_system = nullptr; | |
| 8754 | 8379 | fil_space_crypt_cleanup(); | |
| 8755 | } | ||
| 8756 | |||
| 8757 | #ifndef UNIV_HOTBACKUP | ||
| 8758 | /** Initializes the buffer control block used by fil_tablespace_iterate. | ||
| 8759 | @param[in] block Pointer to the control block | ||
| 8760 | @param[in] frame Pointer to buffer frame */ | ||
| 8761 | 572 | static void fil_buf_block_init(buf_block_t *block, byte *frame) { | |
| 8762 | UNIV_MEM_DESC(frame, UNIV_PAGE_SIZE); | ||
| 8763 | |||
| 8764 | 572 | block->frame = frame; | |
| 8765 | |||
| 8766 | 572 | block->page.init_io_fix(); | |
| 8767 | /* There are assertions that check for this. */ | ||
| 8768 | 572 | block->page.buf_fix_count.store(1); | |
| 8769 | 572 | block->page.state = BUF_BLOCK_READY_FOR_USE; | |
| 8770 | |||
| 8771 | 572 | page_zip_des_init(&block->page.zip); | |
| 8772 | 572 | } | |
| 8773 | |||
| 8774 | struct Fil_page_iterator { | ||
| 8775 | /** File handle */ | ||
| 8776 | pfs_os_file_t m_file; | ||
| 8777 | |||
| 8778 | /** File path name */ | ||
| 8779 | const char *m_filepath; | ||
| 8780 | |||
| 8781 | /** From where to start */ | ||
| 8782 | os_offset_t m_start; | ||
| 8783 | |||
| 8784 | /** Where to stop */ | ||
| 8785 | os_offset_t m_end; | ||
| 8786 | |||
| 8787 | /* File size in bytes */ | ||
| 8788 | os_offset_t m_file_size; | ||
| 8789 | |||
| 8790 | /** Page size */ | ||
| 8791 | size_t m_page_size; | ||
| 8792 | |||
| 8793 | /** Number of pages to use for I/O */ | ||
| 8794 | size_t m_n_io_buffers; | ||
| 8795 | |||
| 8796 | /** Buffer to use for IO */ | ||
| 8797 | byte *m_io_buffer; | ||
| 8798 | |||
| 8799 | /** Encryption key */ | ||
| 8800 | byte *m_encryption_key; | ||
| 8801 | |||
| 8802 | /** Encruption iv */ | ||
| 8803 | byte *m_encryption_iv; | ||
| 8804 | |||
| 8805 | uint m_encryption_key_version; | ||
| 8806 | uint m_encryption_key_id; | ||
| 8807 | fil_space_crypt_t *m_crypt_data; /*!< Crypt data (if encrypted) */ | ||
| 8808 | |||
| 8809 | /** FS Block Size */ | ||
| 8810 | size_t block_size; | ||
| 8811 | |||
| 8812 | /** Compression algorithm to be used if the table needs to be compressed. */ | ||
| 8813 | Compression::Type m_compression_type{}; | ||
| 8814 | }; | ||
| 8815 | |||
| 8816 | /** TODO: This can be made parallel trivially by chunking up the file | ||
| 8817 | and creating a callback per thread. Main benefit will be to use multiple | ||
| 8818 | CPUs for checksums and compressed tables. We have to do compressed tables | ||
| 8819 | block by block right now. Secondly we need to decompress/compress and copy | ||
| 8820 | too much of data. These are CPU intensive. | ||
| 8821 | |||
| 8822 | Iterate over all the pages in the tablespace. | ||
| 8823 | @param[in] iter Tablespace iterator | ||
| 8824 | @param[in,out] block Block to use for IO | ||
| 8825 | @param[in] callback Callback to inspect and update page contents | ||
| 8826 | @retval DB_SUCCESS or error code */ | ||
| 8827 | 570 | static dberr_t fil_iterate(const Fil_page_iterator &iter, buf_block_t *block, | |
| 8828 | PageCallback &callback) { | ||
| 8829 | os_offset_t offset; | ||
| 8830 | size_t n_bytes; | ||
| 8831 | 570 | page_no_t page_no = 0; | |
| 8832 | 570 | space_id_t space_id = callback.get_space_id(); | |
| 8833 | |||
| 8834 | 570 | n_bytes = iter.m_n_io_buffers * iter.m_page_size; | |
| 8835 | |||
| 8836 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 570 times.
|
570 | ut_ad(!srv_read_only_mode); |
| 8837 | |||
| 8838 | /* For old style compressed tables we do a lot of useless copying | ||
| 8839 | for non-index pages. Unfortunately, it is required by | ||
| 8840 | buf_zip_decompress() */ | ||
| 8841 | |||
| 8842 | 570 | ulint read_type = IORequest::READ; | |
| 8843 | 570 | ulint write_type = IORequest::WRITE; | |
| 8844 | |||
| 8845 |
2/2✓ Branch 0 taken 48009 times.
✓ Branch 1 taken 562 times.
|
48571 | for (offset = iter.m_start; offset < iter.m_end; offset += n_bytes) { |
| 8846 |
1/2✓ Branch 0 taken 48009 times.
✗ Branch 1 not taken.
|
48009 | IORequest read_request(read_type); |
| 8847 | |||
| 8848 | 48009 | byte *io_buffer = iter.m_io_buffer; | |
| 8849 | |||
| 8850 | 48009 | block->frame = io_buffer; | |
| 8851 | |||
| 8852 |
2/2✓ Branch 0 taken 3871 times.
✓ Branch 1 taken 44138 times.
|
48009 | if (callback.get_page_size().is_compressed()) { |
| 8853 | 3871 | page_zip_des_init(&block->page.zip); | |
| 8854 |
1/2✓ Branch 0 taken 3871 times.
✗ Branch 1 not taken.
|
3871 | page_zip_set_size(&block->page.zip, iter.m_page_size); |
| 8855 | |||
| 8856 |
1/2✓ Branch 0 taken 3871 times.
✗ Branch 1 not taken.
|
3871 | block->page.size.copy_from( |
| 8857 | ✗ | page_size_t(static_cast<uint32_t>(iter.m_page_size), | |
| 8858 |
2/4✓ Branch 0 taken 3871 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3871 times.
✗ Branch 3 not taken.
|
3871 | static_cast<uint32_t>(univ_page_size.logical()), true)); |
| 8859 | |||
| 8860 | 3871 | block->page.zip.data = block->frame + UNIV_PAGE_SIZE; | |
| 8861 | 3871 | ut_d(block->page.zip.m_external = true); | |
| 8862 |
2/4✓ Branch 0 taken 3871 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3871 times.
|
3871 | ut_ad(iter.m_page_size == callback.get_page_size().physical()); |
| 8863 | |||
| 8864 | 3871 | read_request.mark_page_zip_compressed(); | |
| 8865 | 3871 | read_request.set_zip_page_physical_size(iter.m_page_size); | |
| 8866 | |||
| 8867 | /* Zip IO is done in the compressed page buffer. */ | ||
| 8868 | 3871 | io_buffer = block->page.zip.data; | |
| 8869 | } else { | ||
| 8870 | 44138 | io_buffer = iter.m_io_buffer; | |
| 8871 | } | ||
| 8872 | |||
| 8873 | /* We have to read the exact number of bytes. Otherwise the | ||
| 8874 | InnoDB IO functions croak on failed reads. */ | ||
| 8875 | |||
| 8876 | 48009 | n_bytes = static_cast<ulint>( | |
| 8877 | 48009 | std::min(static_cast<os_offset_t>(n_bytes), iter.m_end - offset)); | |
| 8878 | |||
| 8879 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48009 times.
|
48009 | ut_ad(n_bytes > 0); |
| 8880 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48009 times.
|
48009 | ut_ad(!(n_bytes % iter.m_page_size)); |
| 8881 | |||
| 8882 | 48009 | const bool encrypted_with_keyring = | |
| 8883 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48009 times.
|
48009 | iter.m_crypt_data != NULL && |
| 8884 | ✗ | iter.m_crypt_data->type != CRYPT_SCHEME_UNENCRYPTED; | |
| 8885 | dberr_t err; | ||
| 8886 | 48009 | read_request.block_size(iter.block_size); | |
| 8887 | |||
| 8888 | /* For encrypted table, set encryption information. */ | ||
| 8889 | |||
| 8890 |
5/6✓ Branch 0 taken 31021 times.
✓ Branch 1 taken 16988 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 31021 times.
✓ Branch 4 taken 16944 times.
✓ Branch 5 taken 44 times.
|
48009 | if ((iter.m_encryption_key != NULL || encrypted_with_keyring) && |
| 8891 | offset != 0) { | ||
| 8892 |
4/8✗ Branch 0 not taken.
✓ Branch 1 taken 16944 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16944 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 16944 times.
✓ Branch 6 taken 16944 times.
✗ Branch 7 not taken.
|
33888 | read_request.encryption_key( |
| 8893 | ✗ | encrypted_with_keyring ? iter.m_crypt_data->tablespace_key | |
| 8894 | : iter.m_encryption_key, | ||
| 8895 | Encryption::KEY_LEN, | ||
| 8896 | ✗ | encrypted_with_keyring ? iter.m_crypt_data->iv : iter.m_encryption_iv, | |
| 8897 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16944 times.
|
16944 | 0, iter.m_encryption_key_id, |
| 8898 | ✗ | encrypted_with_keyring ? iter.m_crypt_data->tablespace_key : nullptr, | |
| 8899 | ✗ | encrypted_with_keyring ? iter.m_crypt_data->uuid : nullptr, nullptr); | |
| 8900 | |||
| 8901 |
1/2✓ Branch 0 taken 16944 times.
✗ Branch 1 not taken.
|
16944 | read_request.encryption_algorithm(Encryption::AES); |
| 8902 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16944 times.
|
16944 | if (iter.m_crypt_data) { |
| 8903 | ✗ | read_request.encryption_rotation( | |
| 8904 | ✗ | iter.m_crypt_data->encryption_rotation); | |
| 8905 | } else | ||
| 8906 |
1/2✓ Branch 0 taken 16944 times.
✗ Branch 1 not taken.
|
16944 | read_request.encryption_rotation(Encryption_rotation::NO_ROTATION); |
| 8907 | } | ||
| 8908 | |||
| 8909 |
1/2✓ Branch 0 taken 48007 times.
✗ Branch 1 not taken.
|
48009 | err = os_file_read(read_request, iter.m_filepath, iter.m_file, io_buffer, |
| 8910 | offset, (ulint)n_bytes); | ||
| 8911 | |||
| 8912 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48007 times.
|
48007 | if (err != DB_SUCCESS) { |
| 8913 | ✗ | ib::error(ER_IB_MSG_335) << "os_file_read() failed"; | |
| 8914 | |||
| 8915 | ✗ | return err; | |
| 8916 | } | ||
| 8917 | |||
| 8918 | size_t n_pages_read; | ||
| 8919 | 48007 | bool updated = false; | |
| 8920 | 48007 | os_offset_t page_off = offset; | |
| 8921 | |||
| 8922 | 48007 | n_pages_read = (ulint)n_bytes / iter.m_page_size; | |
| 8923 | |||
| 8924 |
2/2✓ Branch 0 taken 48007 times.
✓ Branch 1 taken 48001 times.
|
96008 | for (size_t i = 0; i < n_pages_read; ++i) { |
| 8925 |
1/2✓ Branch 0 taken 48007 times.
✗ Branch 1 not taken.
|
48007 | buf_block_set_file_page(block, page_id_t(space_id, page_no++)); |
| 8926 | |||
| 8927 | /* We are going to modify the page. Add to page tracking system. */ | ||
| 8928 |
1/2✓ Branch 0 taken 48007 times.
✗ Branch 1 not taken.
|
48007 | arch_page_sys->track_page(&block->page, LSN_MAX, LSN_MAX, true); |
| 8929 | |||
| 8930 |
3/4✓ Branch 0 taken 48007 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 48001 times.
|
48007 | if ((err = callback(page_off, block)) != DB_SUCCESS) { |
| 8931 | 6 | return err; | |
| 8932 | |||
| 8933 |
1/2✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
|
48001 | } else if (!updated) { |
| 8934 |
1/2✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
|
48001 | updated = buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE; |
| 8935 | } | ||
| 8936 | |||
| 8937 |
1/2✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
|
48001 | buf_block_set_state(block, BUF_BLOCK_NOT_USED); |
| 8938 |
1/2✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
|
48001 | buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE); |
| 8939 | |||
| 8940 | 48001 | page_off += iter.m_page_size; | |
| 8941 | 48001 | block->frame += iter.m_page_size; | |
| 8942 | } | ||
| 8943 | |||
| 8944 |
1/2✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
|
48001 | IORequest write_request(write_type); |
| 8945 | 48001 | write_request.block_size(iter.block_size); | |
| 8946 | |||
| 8947 | /* For encrypted table, set encryption information. */ | ||
| 8948 |
4/4✓ Branch 0 taken 16986 times.
✓ Branch 1 taken 31015 times.
✓ Branch 2 taken 16942 times.
✓ Branch 3 taken 44 times.
|
48001 | if (iter.m_encryption_key != NULL && offset != 0 && |
| 8949 |
1/2✓ Branch 0 taken 16942 times.
✗ Branch 1 not taken.
|
16942 | iter.m_crypt_data == NULL) { |
| 8950 | 16942 | write_request.encryption_key( | |
| 8951 | 16942 | iter.m_encryption_key, Encryption::KEY_LEN, iter.m_encryption_iv, | |
| 8952 |
1/2✓ Branch 0 taken 16942 times.
✗ Branch 1 not taken.
|
16942 | iter.m_encryption_key_version, iter.m_encryption_key_id, nullptr, |
| 8953 | nullptr, nullptr); | ||
| 8954 |
1/2✓ Branch 0 taken 16942 times.
✗ Branch 1 not taken.
|
16942 | write_request.encryption_algorithm(Encryption::AES); |
| 8955 |
3/4✓ Branch 0 taken 30492 times.
✓ Branch 1 taken 567 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 30492 times.
|
31059 | } else if (offset != 0 && iter.m_crypt_data) { |
| 8956 | ✗ | write_request.encryption_key( | |
| 8957 | ✗ | iter.m_encryption_key, Encryption::KEY_LEN, iter.m_encryption_iv, | |
| 8958 | ✗ | iter.m_encryption_key_version, iter.m_crypt_data->key_id, nullptr, | |
| 8959 | ✗ | iter.m_crypt_data->uuid, nullptr); | |
| 8960 | |||
| 8961 | ✗ | write_request.encryption_algorithm(Encryption::KEYRING); | |
| 8962 | |||
| 8963 | ✗ | if (callback.get_page_size().is_compressed()) { | |
| 8964 | ✗ | write_request.mark_page_zip_compressed(); | |
| 8965 | ✗ | write_request.set_zip_page_physical_size(iter.m_page_size); | |
| 8966 | } | ||
| 8967 | } | ||
| 8968 | |||
| 8969 | /* For compressed table, set compressed information. | ||
| 8970 | @note os_file_compress_page() function expects that the page size is a | ||
| 8971 | multiple of OS punch hole size so we make sure it's true before turning | ||
| 8972 | on compression. */ | ||
| 8973 | 97282 | if (iter.m_compression_type != Compression::Type::NONE && | |
| 8974 |
6/8✓ Branch 0 taken 1280 times.
✓ Branch 1 taken 46721 times.
✓ Branch 2 taken 1280 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1280 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1280 times.
✓ Branch 7 taken 46721 times.
|
49281 | IORequest::is_punch_hole_supported() && |
| 8975 |
1/2✓ Branch 0 taken 1280 times.
✗ Branch 1 not taken.
|
1280 | !(srv_page_size % iter.block_size)) { |
| 8976 |
1/2✓ Branch 0 taken 1280 times.
✗ Branch 1 not taken.
|
1280 | write_request.compression_algorithm(iter.m_compression_type); |
| 8977 | |||
| 8978 | /* In the case of import since we're doing compression for the first time | ||
| 8979 | we would like to ignore any optimisations to not do punch hole. So force | ||
| 8980 | the punch hole. */ | ||
| 8981 |
1/2✓ Branch 0 taken 1280 times.
✗ Branch 1 not taken.
|
1280 | write_request.disable_punch_hole_optimisation(); |
| 8982 | } | ||
| 8983 | |||
| 8984 | /* A page was updated in the set, write back to disk. */ | ||
| 8985 | |||
| 8986 |
4/8✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48001 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 48001 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 48001 times.
|
48001 | if (updated && (err = os_file_write(write_request, iter.m_filepath, |
| 8987 | iter.m_file, io_buffer, offset, | ||
| 8988 | (ulint)n_bytes)) != DB_SUCCESS) { | ||
| 8989 | /* This is not a hard error */ | ||
| 8990 | ✗ | if (err == DB_IO_NO_PUNCH_HOLE) { | |
| 8991 | ✗ | err = DB_SUCCESS; | |
| 8992 | ✗ | write_type &= ~IORequest::PUNCH_HOLE; | |
| 8993 | |||
| 8994 | } else { | ||
| 8995 | ✗ | ib::error(ER_IB_MSG_336) << "os_file_write() failed"; | |
| 8996 | |||
| 8997 | ✗ | return err; | |
| 8998 | } | ||
| 8999 | } | ||
| 9000 |
3/4✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48001 times.
✓ Branch 3 taken 6 times.
|
48007 | } |
| 9001 | |||
| 9002 | 562 | return DB_SUCCESS; | |
| 9003 | } | ||
| 9004 | |||
| 9005 | 1294 | void fil_adjust_name_import(dict_table_t *table [[maybe_unused]], | |
| 9006 | const char *path, | ||
| 9007 | ib_file_suffix extn [[maybe_unused]]) { | ||
| 9008 | /* Try to open with current name first. */ | ||
| 9009 |
3/4✓ Branch 0 taken 1294 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1225 times.
✓ Branch 3 taken 69 times.
|
1294 | if (os_file_exists(path)) { |
| 9010 | 1225 | return; | |
| 9011 | } | ||
| 9012 | |||
| 9013 | /* On failure we need to check if file exists in different letter case | ||
| 9014 | for partitioned table. */ | ||
| 9015 | |||
| 9016 | /* Safe check. Never needed on Windows. */ | ||
| 9017 | #ifndef _WIN32 | ||
| 9018 | /* Needed only for case sensitive file system. */ | ||
| 9019 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
|
69 | if (lower_case_file_system) { |
| 9020 | ✗ | return; | |
| 9021 | } | ||
| 9022 | |||
| 9023 | /* Only needed for partition file. */ | ||
| 9024 |
4/6✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 69 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 42 times.
|
69 | if (!dict_name::is_partition(table->name.m_name)) { |
| 9025 | 27 | return; | |
| 9026 | } | ||
| 9027 | |||
| 9028 | /* Get Import directory path. */ | ||
| 9029 |
1/2✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
|
42 | std::string import_dir(path); |
| 9030 | 42 | Fil_path::normalize(import_dir); | |
| 9031 | |||
| 9032 | 42 | auto pos = import_dir.find_last_of(Fil_path::SEPARATOR); | |
| 9033 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if (pos == std::string::npos) { |
| 9034 | ✗ | import_dir.assign(Fil_path::DOT_SLASH); | |
| 9035 | |||
| 9036 | } else { | ||
| 9037 |
1/2✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
|
42 | import_dir.resize(pos + 1); |
| 9038 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | ut_ad(Fil_path::is_separator(import_dir.back())); |
| 9039 | } | ||
| 9040 | |||
| 9041 | /* Walk through all files under the directory and match the import file | ||
| 9042 | after adjusting case. This is a safe check to allow files exported from | ||
| 9043 | earlier versions where the case for partition name and separator could | ||
| 9044 | be different. */ | ||
| 9045 | 42 | bool found_path = false; | |
| 9046 | 42 | std::string saved_path; | |
| 9047 | |||
| 9048 |
1/2✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
|
42 | Dir_Walker::walk(import_dir, false, [&](const std::string &file_path) { |
| 9049 | /* Skip entry if already found. */ | ||
| 9050 |
2/2✓ Branch 0 taken 282 times.
✓ Branch 1 taken 267 times.
|
549 | if (found_path) { |
| 9051 | 519 | return; | |
| 9052 | } | ||
| 9053 | /* Check only for partition files. */ | ||
| 9054 |
3/4✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 259 times.
|
267 | if (!dict_name::is_partition(file_path)) { |
| 9055 | 8 | return; | |
| 9056 | } | ||
| 9057 | |||
| 9058 | /* Extract table name from path. */ | ||
| 9059 | 259 | std::string table_name; | |
| 9060 |
3/4✓ Branch 0 taken 259 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 148 times.
✓ Branch 3 taken 111 times.
|
259 | if (!Fil_path::parse_file_path(file_path, extn, table_name)) { |
| 9061 | /* Not a valid file-per-table path */ | ||
| 9062 | 148 | return; | |
| 9063 | } | ||
| 9064 | |||
| 9065 | /* Check if the file name would match after correcting the case. */ | ||
| 9066 |
1/2✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
|
111 | dict_name::rebuild(table_name); |
| 9067 |
2/2✓ Branch 0 taken 81 times.
✓ Branch 1 taken 30 times.
|
111 | if (table_name.compare(table->name.m_name) != 0) { |
| 9068 | 81 | return; | |
| 9069 | } | ||
| 9070 | |||
| 9071 |
1/2✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
|
30 | saved_path.assign(file_path); |
| 9072 | 30 | found_path = true; | |
| 9073 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 229 times.
|
259 | }); |
| 9074 | |||
| 9075 | /* Check and rename the import file name. */ | ||
| 9076 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 12 times.
|
42 | if (found_path) { |
| 9077 |
1/2✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
|
30 | fil_rename_partition_file(saved_path, extn, false, true); |
| 9078 | } | ||
| 9079 | #endif /* !WIN32 */ | ||
| 9080 | |||
| 9081 | 42 | return; | |
| 9082 | 42 | } | |
| 9083 | |||
| 9084 | 584 | dberr_t fil_tablespace_iterate(dict_table_t *table, ulint n_io_buffers, | |
| 9085 | Compression::Type compression_type, | ||
| 9086 | PageCallback &callback) { | ||
| 9087 | dberr_t err; | ||
| 9088 | pfs_os_file_t file; | ||
| 9089 | char *filepath; | ||
| 9090 | bool success; | ||
| 9091 | |||
| 9092 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 584 times.
|
584 | ut_a(n_io_buffers > 0); |
| 9093 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 584 times.
|
584 | ut_ad(!srv_read_only_mode); |
| 9094 | |||
| 9095 |
3/4✓ Branch 0 taken 584 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 582 times.
|
584 | DBUG_EXECUTE_IF("ib_import_trigger_corruption_1", return DB_CORRUPTION;); |
| 9096 | |||
| 9097 | /* Make sure the data_dir_path is set. */ | ||
| 9098 |
1/2✓ Branch 0 taken 582 times.
✗ Branch 1 not taken.
|
582 | dd_get_and_save_data_dir_path<dd::Table>(table, nullptr, false); |
| 9099 | |||
| 9100 |
1/2✓ Branch 0 taken 582 times.
✗ Branch 1 not taken.
|
582 | std::string path = dict_table_get_datadir(table); |
| 9101 | |||
| 9102 |
2/4✓ Branch 0 taken 582 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 582 times.
✗ Branch 3 not taken.
|
582 | filepath = Fil_path::make(path, table->name.m_name, IBD, true); |
| 9103 | |||
| 9104 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 582 times.
|
582 | if (filepath == nullptr) { |
| 9105 | ✗ | return DB_OUT_OF_MEMORY; | |
| 9106 | } | ||
| 9107 | |||
| 9108 | /* Adjust filename for partition file if in different letter case. */ | ||
| 9109 |
1/2✓ Branch 0 taken 582 times.
✗ Branch 1 not taken.
|
582 | fil_adjust_name_import(table, filepath, IBD); |
| 9110 | |||
| 9111 |
1/2✓ Branch 0 taken 582 times.
✗ Branch 1 not taken.
|
582 | file = os_file_create_simple_no_error_handling( |
| 9112 | innodb_data_file_key, filepath, OS_FILE_OPEN, OS_FILE_READ_WRITE, | ||
| 9113 | srv_read_only_mode, &success); | ||
| 9114 | |||
| 9115 |
2/14✓ Branch 0 taken 582 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 582 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
582 | DBUG_EXECUTE_IF("fil_tablespace_iterate_failure", { |
| 9116 | static bool once; | ||
| 9117 | |||
| 9118 | if (!once || ut::random_from_interval(0, 10) == 5) { | ||
| 9119 | once = true; | ||
| 9120 | success = false; | ||
| 9121 | os_file_close(file); | ||
| 9122 | } | ||
| 9123 | }); | ||
| 9124 | |||
| 9125 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 572 times.
|
582 | if (!success) { |
| 9126 | /* The following call prints an error message */ | ||
| 9127 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | os_file_get_last_error(true); |
| 9128 | |||
| 9129 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
20 | ib::error(ER_IB_MSG_337) << "Trying to import a tablespace, but could not" |
| 9130 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | " open the tablespace file " |
| 9131 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | << filepath; |
| 9132 | |||
| 9133 | 10 | ut::free(filepath); | |
| 9134 | |||
| 9135 | 10 | return DB_TABLESPACE_NOT_FOUND; | |
| 9136 | |||
| 9137 | } else { | ||
| 9138 | 572 | err = DB_SUCCESS; | |
| 9139 | } | ||
| 9140 | |||
| 9141 | /* Set File System Block Size */ | ||
| 9142 | size_t block_size; | ||
| 9143 | { | ||
| 9144 | os_file_stat_t stat_info; | ||
| 9145 | |||
| 9146 |
1/2✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
|
572 | ut_d(dberr_t err =) os_file_get_status(filepath, &stat_info, false, false); |
| 9147 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 572 times.
|
572 | ut_ad(err == DB_SUCCESS); |
| 9148 | |||
| 9149 | 572 | block_size = stat_info.block_size; | |
| 9150 | } | ||
| 9151 | |||
| 9152 | 572 | callback.set_file(filepath, file); | |
| 9153 | |||
| 9154 |
1/2✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
|
572 | os_offset_t file_size = os_file_get_size(file); |
| 9155 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 572 times.
|
572 | ut_a(file_size != (os_offset_t)-1); |
| 9156 | |||
| 9157 | /* The block we will use for every physical page */ | ||
| 9158 | buf_block_t *block; | ||
| 9159 | |||
| 9160 | block = reinterpret_cast<buf_block_t *>( | ||
| 9161 | 572 | ut::zalloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, sizeof(*block))); | |
| 9162 | |||
| 9163 |
1/2✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
|
572 | mutex_create(LATCH_ID_BUF_BLOCK_MUTEX, &block->mutex); |
| 9164 | |||
| 9165 | /* Allocate a page to read in the tablespace header, so that we | ||
| 9166 | can determine the page size and zip size (if it is compressed). | ||
| 9167 | We allocate an extra page in case it is a compressed table. One | ||
| 9168 | page is to ensure alignment. */ | ||
| 9169 | |||
| 9170 | byte *page = static_cast<byte *>( | ||
| 9171 | 572 | ut::aligned_alloc(2 * UNIV_PAGE_SIZE, UNIV_PAGE_SIZE)); | |
| 9172 | |||
| 9173 | 572 | fil_buf_block_init(block, page); | |
| 9174 | |||
| 9175 | /* Read the first page and determine the page and zip size. */ | ||
| 9176 | |||
| 9177 |
1/2✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
|
572 | IORequest request(IORequest::READ); |
| 9178 | |||
| 9179 |
1/2✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
|
572 | err = os_file_read_first_page(request, path.c_str(), file, page, |
| 9180 | UNIV_PAGE_SIZE); | ||
| 9181 | |||
| 9182 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 572 times.
|
572 | if (err != DB_SUCCESS) { |
| 9183 | ✗ | err = DB_IO_ERROR; | |
| 9184 | |||
| 9185 |
2/4✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 572 times.
✗ Branch 3 not taken.
|
572 | } else if ((err = callback.init(file_size, block)) == DB_SUCCESS) { |
| 9186 | 572 | Fil_page_iterator iter; | |
| 9187 | |||
| 9188 | 572 | iter.m_file = file; | |
| 9189 | 572 | iter.m_start = 0; | |
| 9190 | 572 | iter.m_end = file_size; | |
| 9191 | 572 | iter.m_filepath = filepath; | |
| 9192 | 572 | iter.m_file_size = file_size; | |
| 9193 | 572 | iter.m_n_io_buffers = n_io_buffers; | |
| 9194 |
1/2✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
|
572 | iter.m_page_size = callback.get_page_size().physical(); |
| 9195 | 572 | iter.block_size = block_size; | |
| 9196 | |||
| 9197 | 572 | iter.m_compression_type = compression_type; | |
| 9198 | |||
| 9199 | /* Check encryption is matched or not. */ | ||
| 9200 |
1/2✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
|
572 | ulint space_flags = callback.get_space_flags(); |
| 9201 | 572 | iter.m_crypt_data = | |
| 9202 |
1/2✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
|
572 | fil_space_read_crypt_data(callback.get_page_size(), page); |
| 9203 | |||
| 9204 | /* read (optional) crypt data */ | ||
| 9205 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 572 times.
|
572 | if (iter.m_crypt_data && |
| 9206 | ✗ | iter.m_crypt_data->type != CRYPT_SCHEME_UNENCRYPTED) { | |
| 9207 | ✗ | ut_ad(FSP_FLAGS_GET_ENCRYPTION(space_flags)); | |
| 9208 | ✗ | iter.m_encryption_key_id = iter.m_crypt_data->key_id; | |
| 9209 | |||
| 9210 | ✗ | Encryption::get_latest_tablespace_key( | |
| 9211 | ✗ | iter.m_crypt_data->key_id, iter.m_crypt_data->uuid, | |
| 9212 | &iter.m_encryption_key_version, &iter.m_encryption_key); | ||
| 9213 | ✗ | if (iter.m_encryption_key == NULL) err = DB_IO_DECRYPT_FAIL; | |
| 9214 | } else { | ||
| 9215 | /* Set encryption info. */ | ||
| 9216 | 572 | iter.m_encryption_key = table->encryption_key; | |
| 9217 | 572 | iter.m_encryption_iv = table->encryption_iv; | |
| 9218 | 572 | iter.m_encryption_key_version = ~0; // TODO:Robert:flipping bits so to | |
| 9219 | // make this a marker that tablespace | ||
| 9220 | // key id used | ||
| 9221 | } | ||
| 9222 | |||
| 9223 | /* Check encryption is matched or not. */ | ||
| 9224 |
5/6✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 526 times.
✓ Branch 4 taken 46 times.
✓ Branch 5 taken 526 times.
|
572 | if (err == DB_SUCCESS && FSP_FLAGS_GET_ENCRYPTION(space_flags)) { |
| 9225 |
3/4✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 44 times.
|
46 | if (!dd_is_table_in_encrypted_tablespace(table)) { |
| 9226 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | ib::error(ER_IB_MSG_338) << "Table is not in an encrypted tablespace," |
| 9227 | " but the data file intended for import" | ||
| 9228 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | " is an encrypted tablespace"; |
| 9229 | |||
| 9230 | 2 | err = DB_IO_NO_ENCRYPT_TABLESPACE; | |
| 9231 | } else { | ||
| 9232 | /* encryption_key must have been populated while reading CFP file. */ | ||
| 9233 |
3/6✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 44 times.
|
44 | ut_ad(table->encryption_key != nullptr && |
| 9234 | table->encryption_iv != nullptr); | ||
| 9235 | |||
| 9236 |
1/2✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
|
44 | if (table->encryption_key == nullptr || |
| 9237 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | table->encryption_iv == nullptr) { |
| 9238 | ✗ | err = DB_ERROR; | |
| 9239 | } | ||
| 9240 | } | ||
| 9241 | } | ||
| 9242 | |||
| 9243 |
2/2✓ Branch 0 taken 570 times.
✓ Branch 1 taken 2 times.
|
572 | if (err == DB_SUCCESS) { |
| 9244 | /* Compressed pages can't be optimised for block IO | ||
| 9245 | for now. We do the IMPORT page by page. */ | ||
| 9246 | |||
| 9247 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 545 times.
|
570 | if (callback.get_page_size().is_compressed()) { |
| 9248 | 25 | iter.m_n_io_buffers = 1; | |
| 9249 |
2/4✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 25 times.
|
25 | ut_a(iter.m_page_size == callback.get_page_size().physical()); |
| 9250 | } | ||
| 9251 | |||
| 9252 | /** Add an extra page for compressed page scratch | ||
| 9253 | area. */ | ||
| 9254 | 1140 | iter.m_io_buffer = static_cast<byte *>(ut::aligned_alloc( | |
| 9255 | 570 | (1 + iter.m_n_io_buffers) * UNIV_PAGE_SIZE, UNIV_PAGE_SIZE)); | |
| 9256 | |||
| 9257 |
1/2✓ Branch 0 taken 568 times.
✗ Branch 1 not taken.
|
570 | err = fil_iterate(iter, block, callback); |
| 9258 | |||
| 9259 | 568 | ut::aligned_free(iter.m_io_buffer); | |
| 9260 | } | ||
| 9261 | |||
| 9262 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 570 times.
|
570 | if (iter.m_crypt_data) { |
| 9263 | ✗ | fil_space_destroy_crypt_data(&iter.m_crypt_data); | |
| 9264 | ✗ | if (iter.m_encryption_key != NULL) my_free(iter.m_encryption_key); | |
| 9265 | } | ||
| 9266 | } | ||
| 9267 | |||
| 9268 |
2/2✓ Branch 0 taken 562 times.
✓ Branch 1 taken 8 times.
|
570 | if (err == DB_SUCCESS) { |
| 9269 |
2/4✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 562 times.
✗ Branch 3 not taken.
|
562 | ib::info(ER_IB_MSG_339) << "Sync to disk"; |
| 9270 | |||
| 9271 |
2/4✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 562 times.
|
562 | if (!os_file_flush(file)) { |
| 9272 | ✗ | ib::info(ER_IB_MSG_340) << "os_file_flush() failed!"; | |
| 9273 | ✗ | err = DB_IO_ERROR; | |
| 9274 | } else { | ||
| 9275 |
2/4✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 562 times.
✗ Branch 3 not taken.
|
562 | ib::info(ER_IB_MSG_341) << "Sync to disk - done!"; |
| 9276 | } | ||
| 9277 | } | ||
| 9278 | |||
| 9279 |
1/2✓ Branch 0 taken 570 times.
✗ Branch 1 not taken.
|
570 | os_file_close(file); |
| 9280 | |||
| 9281 | 570 | ut::aligned_free(page); | |
| 9282 | 570 | ut::free(filepath); | |
| 9283 | |||
| 9284 |
1/2✓ Branch 0 taken 570 times.
✗ Branch 1 not taken.
|
570 | mutex_free(&block->mutex); |
| 9285 | |||
| 9286 | 570 | ut::free(block); | |
| 9287 | |||
| 9288 | 570 | return err; | |
| 9289 | 580 | } | |
| 9290 | #endif /* !UNIV_HOTBACKUP */ | ||
| 9291 | |||
| 9292 | /** Set the tablespace table size. | ||
| 9293 | @param[in] page a page belonging to the tablespace */ | ||
| 9294 | 572 | void PageCallback::set_page_size(const buf_frame_t *page) UNIV_NOTHROW { | |
| 9295 |
1/2✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
|
572 | m_page_size.copy_from(fsp_header_get_page_size(page)); |
| 9296 | 572 | } | |
| 9297 | |||
| 9298 | /** Delete the tablespace file and any related files like .cfg. | ||
| 9299 | This should not be called for temporary tables. | ||
| 9300 | @param[in] path File path of the IBD tablespace | ||
| 9301 | @return true on success */ | ||
| 9302 | 197 | bool fil_delete_file(const char *path) { | |
| 9303 | 197 | bool success = true; | |
| 9304 | |||
| 9305 | /* Force a delete of any stale .ibd files that are lying around. */ | ||
| 9306 | 197 | success = os_file_delete_if_exists(innodb_data_file_key, path, nullptr); | |
| 9307 | |||
| 9308 |
2/4✓ Branch 0 taken 197 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 197 times.
✗ Branch 3 not taken.
|
197 | char *cfg_filepath = Fil_path::make_cfg(path); |
| 9309 | |||
| 9310 |
1/2✓ Branch 0 taken 197 times.
✗ Branch 1 not taken.
|
197 | if (cfg_filepath != nullptr) { |
| 9311 | 197 | os_file_delete_if_exists(innodb_data_file_key, cfg_filepath, nullptr); | |
| 9312 | |||
| 9313 | 197 | ut::free(cfg_filepath); | |
| 9314 | } | ||
| 9315 | |||
| 9316 |
2/4✓ Branch 0 taken 197 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 197 times.
✗ Branch 3 not taken.
|
197 | char *cfp_filepath = Fil_path::make_cfp(path); |
| 9317 | |||
| 9318 |
1/2✓ Branch 0 taken 197 times.
✗ Branch 1 not taken.
|
197 | if (cfp_filepath != nullptr) { |
| 9319 | 197 | os_file_delete_if_exists(innodb_data_file_key, cfp_filepath, nullptr); | |
| 9320 | |||
| 9321 | 197 | ut::free(cfp_filepath); | |
| 9322 | } | ||
| 9323 | |||
| 9324 | 197 | return success; | |
| 9325 | } | ||
| 9326 | |||
| 9327 | #ifndef UNIV_HOTBACKUP | ||
| 9328 | 35694 | dberr_t fil_rename_precheck(const dict_table_t *old_table, | |
| 9329 | const dict_table_t *new_table, | ||
| 9330 | const char *tmp_name) { | ||
| 9331 |
1/2✓ Branch 0 taken 35694 times.
✗ Branch 1 not taken.
|
35694 | bool old_is_file_per_table = dict_table_is_file_per_table(old_table); |
| 9332 |
1/2✓ Branch 0 taken 35694 times.
✗ Branch 1 not taken.
|
35694 | bool new_is_file_per_table = dict_table_is_file_per_table(new_table); |
| 9333 | |||
| 9334 | /* If neither table is file-per-table, there will be no renaming of files. */ | ||
| 9335 |
4/4✓ Branch 0 taken 13235 times.
✓ Branch 1 taken 22459 times.
✓ Branch 2 taken 13129 times.
✓ Branch 3 taken 106 times.
|
35694 | if (!old_is_file_per_table && !new_is_file_per_table) { |
| 9336 | 13129 | return DB_SUCCESS; | |
| 9337 | } | ||
| 9338 | |||
| 9339 | 43585 | auto fetch_path = [](std::string &path, const dict_table_t *source_table, | |
| 9340 | bool fpt) -> dberr_t { | ||
| 9341 | 43585 | char *path_ptr{}; | |
| 9342 | |||
| 9343 | /* It is possible that the file could be present in a directory outside of | ||
| 9344 | the data directory (possible because of innodb_directories option), so | ||
| 9345 | fetch the path accordingly. | ||
| 9346 | |||
| 9347 | We are only interested in fetching the right path for file-per-table | ||
| 9348 | tablespaces as during file_rename_tablespace_check the source table should | ||
| 9349 | always exist and we do the rename for only source tables which are | ||
| 9350 | file-per-table tablspaces. */ | ||
| 9351 |
6/6✓ Branch 0 taken 43479 times.
✓ Branch 1 taken 106 times.
✓ Branch 2 taken 43471 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 43471 times.
✓ Branch 5 taken 114 times.
|
43585 | if (fpt && !dict_table_is_discarded(source_table)) { |
| 9352 | 43471 | path_ptr = fil_space_get_first_path(source_table->space); | |
| 9353 | |||
| 9354 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43471 times.
|
43471 | if (path_ptr == nullptr) { |
| 9355 | ✗ | return DB_TABLESPACE_NOT_FOUND; | |
| 9356 | } | ||
| 9357 | } else { | ||
| 9358 |
1/2✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
|
114 | auto dir = dict_table_get_datadir(source_table); |
| 9359 | |||
| 9360 | path_ptr = | ||
| 9361 |
2/4✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 114 times.
✗ Branch 3 not taken.
|
114 | Fil_path::make(dir, source_table->name.m_name, IBD, !dir.empty()); |
| 9362 | |||
| 9363 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
|
114 | if (path_ptr == nullptr) { |
| 9364 | ✗ | return DB_OUT_OF_MEMORY; | |
| 9365 | } | ||
| 9366 |
1/2✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
|
114 | } |
| 9367 | |||
| 9368 | 43585 | path.assign(path_ptr); | |
| 9369 | 43585 | ut::free(path_ptr); | |
| 9370 | |||
| 9371 | 43585 | return DB_SUCCESS; | |
| 9372 | }; | ||
| 9373 | |||
| 9374 | 22565 | std::string old_path; | |
| 9375 | |||
| 9376 |
1/2✓ Branch 0 taken 22565 times.
✗ Branch 1 not taken.
|
22565 | auto err = fetch_path(old_path, old_table, old_is_file_per_table); |
| 9377 | |||
| 9378 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22565 times.
|
22565 | if (err != DB_SUCCESS) { |
| 9379 | ✗ | return err; | |
| 9380 | } | ||
| 9381 | |||
| 9382 |
2/2✓ Branch 0 taken 22459 times.
✓ Branch 1 taken 106 times.
|
22565 | if (old_is_file_per_table) { |
| 9383 | std::string tmp_path = | ||
| 9384 |
3/6✓ Branch 0 taken 22459 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22459 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 22459 times.
✗ Branch 5 not taken.
|
44918 | Fil_path::make_new_path(old_path.c_str(), tmp_name, IBD); |
| 9385 | |||
| 9386 | /* Temp filepath must not exist. */ | ||
| 9387 |
1/2✓ Branch 0 taken 22459 times.
✗ Branch 1 not taken.
|
22459 | err = fil_rename_tablespace_check(old_table->space, old_path.c_str(), |
| 9388 | tmp_path.c_str(), | ||
| 9389 | 22459 | dict_table_is_discarded(old_table)); | |
| 9390 | |||
| 9391 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22459 times.
|
22459 | if (err != DB_SUCCESS) { |
| 9392 | ✗ | return err; | |
| 9393 | } | ||
| 9394 |
1/2✓ Branch 0 taken 22459 times.
✗ Branch 1 not taken.
|
22459 | } |
| 9395 | |||
| 9396 |
2/2✓ Branch 0 taken 21020 times.
✓ Branch 1 taken 1545 times.
|
22565 | if (new_is_file_per_table) { |
| 9397 | 21020 | std::string new_path; | |
| 9398 | |||
| 9399 |
1/2✓ Branch 0 taken 21020 times.
✗ Branch 1 not taken.
|
21020 | err = fetch_path(new_path, new_table, new_is_file_per_table); |
| 9400 | |||
| 9401 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21020 times.
|
21020 | if (err != DB_SUCCESS) { |
| 9402 | ✗ | return err; | |
| 9403 | } | ||
| 9404 | |||
| 9405 | /* Destination filepath must not exist unless this ALTER TABLE starts and | ||
| 9406 | ends with a file_per-table tablespace. */ | ||
| 9407 |
2/2✓ Branch 0 taken 106 times.
✓ Branch 1 taken 20914 times.
|
21020 | if (!old_is_file_per_table) { |
| 9408 |
1/2✓ Branch 0 taken 106 times.
✗ Branch 1 not taken.
|
106 | err = fil_rename_tablespace_check(new_table->space, new_path.c_str(), |
| 9409 | old_path.c_str(), | ||
| 9410 | 106 | dict_table_is_discarded(new_table)); | |
| 9411 | } | ||
| 9412 |
1/2✓ Branch 0 taken 21020 times.
✗ Branch 1 not taken.
|
21020 | } |
| 9413 | |||
| 9414 | 22565 | return err; | |
| 9415 | 22565 | } | |
| 9416 | #endif /* !UNIV_HOTBACKUP */ | ||
| 9417 | |||
| 9418 | /** Note that the file system where the file resides doesn't support PUNCH HOLE. | ||
| 9419 | Called from AIO handlers when IO returns DB_IO_NO_PUNCH_HOLE | ||
| 9420 | @param[in,out] file file to set */ | ||
| 9421 | 1247 | void fil_no_punch_hole(fil_node_t *file) { file->punch_hole = false; } | |
| 9422 | |||
| 9423 | 546922 | dberr_t fil_set_compression(space_id_t space_id, const char *algorithm) { | |
| 9424 | dberr_t err; | ||
| 9425 | 546922 | Compression compression; | |
| 9426 | |||
| 9427 |
3/4✓ Branch 0 taken 451 times.
✓ Branch 1 taken 546473 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 451 times.
|
546924 | if (algorithm == nullptr || strlen(algorithm) == 0) { |
| 9428 | #ifndef UNIV_DEBUG | ||
| 9429 | compression.m_type = Compression::NONE; | ||
| 9430 | #else /* UNIV_DEBUG */ | ||
| 9431 | /* This is a Debug tool for setting compression on all | ||
| 9432 | compressible tables not otherwise specified. */ | ||
| 9433 |
1/2✓ Branch 0 taken 546473 times.
✗ Branch 1 not taken.
|
546473 | switch (srv_debug_compress) { |
| 9434 | 546473 | case Compression::LZ4: | |
| 9435 | case Compression::ZLIB: | ||
| 9436 | case Compression::NONE: | ||
| 9437 | |||
| 9438 | 546473 | compression.m_type = static_cast<Compression::Type>(srv_debug_compress); | |
| 9439 | 546473 | break; | |
| 9440 | |||
| 9441 | ✗ | default: | |
| 9442 | ✗ | compression.m_type = Compression::NONE; | |
| 9443 | } | ||
| 9444 | |||
| 9445 | #endif /* UNIV_DEBUG */ | ||
| 9446 | |||
| 9447 | 546473 | err = DB_SUCCESS; | |
| 9448 | |||
| 9449 | } else { | ||
| 9450 |
1/2✓ Branch 0 taken 451 times.
✗ Branch 1 not taken.
|
451 | err = Compression::check(algorithm, &compression); |
| 9451 | } | ||
| 9452 | |||
| 9453 |
1/2✓ Branch 0 taken 546923 times.
✗ Branch 1 not taken.
|
546924 | fil_space_t *space = fil_space_get(space_id); |
| 9454 | |||
| 9455 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 546923 times.
|
546923 | if (space == nullptr) { |
| 9456 | ✗ | return DB_NOT_FOUND; | |
| 9457 | } | ||
| 9458 | |||
| 9459 |
1/2✓ Branch 0 taken 546924 times.
✗ Branch 1 not taken.
|
546923 | const page_size_t page_size(space->flags); |
| 9460 | |||
| 9461 |
1/2✓ Branch 0 taken 546923 times.
✗ Branch 1 not taken.
|
546924 | if (!fsp_is_file_per_table(space_id, space->flags) || |
| 9462 |
6/10✓ Branch 0 taken 546923 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 546923 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 546924 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 546922 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 546922 times.
|
546923 | fsp_is_system_temporary(space_id) || page_size.is_compressed()) { |
| 9463 | ✗ | return DB_IO_NO_PUNCH_HOLE_TABLESPACE; | |
| 9464 | } | ||
| 9465 | |||
| 9466 | 546922 | space->compression_type = compression.m_type; | |
| 9467 | |||
| 9468 |
2/2✓ Branch 0 taken 308 times.
✓ Branch 1 taken 546614 times.
|
546922 | if (space->compression_type != Compression::NONE) { |
| 9469 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 308 times.
|
308 | if (!space->files.front().punch_hole) { |
| 9470 | ✗ | return DB_IO_NO_PUNCH_HOLE_FS; | |
| 9471 | } | ||
| 9472 | } | ||
| 9473 | |||
| 9474 | 546922 | return err; | |
| 9475 | } | ||
| 9476 | |||
| 9477 | /** Get the compression algorithm for a tablespace. | ||
| 9478 | @param[in] space_id Space ID to check | ||
| 9479 | @return the compression algorithm */ | ||
| 9480 | 642 | Compression::Type fil_get_compression(space_id_t space_id) { | |
| 9481 | 642 | fil_space_t *space = fil_space_get(space_id); | |
| 9482 | |||
| 9483 |
1/2✓ Branch 0 taken 642 times.
✗ Branch 1 not taken.
|
642 | return space == nullptr ? Compression::NONE : space->compression_type; |
| 9484 | } | ||
| 9485 | |||
| 9486 | /** Set the autoextend_size attribute for the tablespace | ||
| 9487 | @param[in] space_id Space ID of tablespace for which to set | ||
| 9488 | @param[in] autoextend_size Value of autoextend_size attribute | ||
| 9489 | @return DB_SUCCESS or error code */ | ||
| 9490 | 323910 | dberr_t fil_set_autoextend_size(space_id_t space_id, uint64_t autoextend_size) { | |
| 9491 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 323910 times.
|
323910 | ut_ad(space_id != TRX_SYS_SPACE); |
| 9492 | |||
| 9493 | 323910 | fil_space_t *space = fil_space_acquire(space_id); | |
| 9494 | |||
| 9495 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 323910 times.
|
323910 | if (space == nullptr) { |
| 9496 | ✗ | return DB_NOT_FOUND; | |
| 9497 | } | ||
| 9498 | |||
| 9499 | 323910 | rw_lock_x_lock(&space->latch, UT_LOCATION_HERE); | |
| 9500 | |||
| 9501 | 323910 | space->autoextend_size_in_bytes = autoextend_size; | |
| 9502 | |||
| 9503 | 323910 | rw_lock_x_unlock(&space->latch); | |
| 9504 | |||
| 9505 | 323910 | fil_space_release(space); | |
| 9506 | |||
| 9507 | 323910 | return DB_SUCCESS; | |
| 9508 | } | ||
| 9509 | |||
| 9510 | /** Set the encryption type for the tablespace | ||
| 9511 | @param[in] space_id Space ID of tablespace for which to set | ||
| 9512 | @param[in] algorithm Encryption algorithm | ||
| 9513 | @param[in] key Encryption key | ||
| 9514 | @param[in] iv Encryption iv | ||
| 9515 | @param[in] acquire_mutex if true acquire fil_sys mutex, else false | ||
| 9516 | @return DB_SUCCESS or error code */ | ||
| 9517 | 2749 | dberr_t fil_set_encryption(space_id_t space_id, Encryption::Type algorithm, | |
| 9518 | byte *key, byte *iv, bool acquire_mutex) { | ||
| 9519 | 2749 | auto shard = fil_system->shard_by_id(space_id); | |
| 9520 | |||
| 9521 |
1/2✓ Branch 0 taken 2749 times.
✗ Branch 1 not taken.
|
2749 | if (acquire_mutex) shard->mutex_acquire(); |
| 9522 | |||
| 9523 | 2749 | fil_space_t *space = shard->get_space_by_id(space_id); | |
| 9524 | |||
| 9525 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2749 times.
|
2749 | if (space == nullptr) { |
| 9526 | ✗ | if (acquire_mutex) { | |
| 9527 | ✗ | shard->mutex_release(); | |
| 9528 | } | ||
| 9529 | ✗ | return DB_NOT_FOUND; | |
| 9530 | } | ||
| 9531 | |||
| 9532 | 2749 | Encryption::set_or_generate(algorithm, key, iv, space->m_encryption_metadata); | |
| 9533 | |||
| 9534 |
2/2✓ Branch 0 taken 2733 times.
✓ Branch 1 taken 16 times.
|
2749 | if (space->crypt_data == nullptr) fsp_flags_set_encryption(space->flags); |
| 9535 | |||
| 9536 |
1/2✓ Branch 0 taken 2749 times.
✗ Branch 1 not taken.
|
2749 | if (acquire_mutex) { |
| 9537 | 2749 | shard->mutex_release(); | |
| 9538 | } | ||
| 9539 | |||
| 9540 | 2749 | return DB_SUCCESS; | |
| 9541 | } | ||
| 9542 | |||
| 9543 | /** Enable encryption of temporary tablespace | ||
| 9544 | @param[in,out] space tablespace object | ||
| 9545 | @return DB_SUCCESS on success, DB_ERROR on failure */ | ||
| 9546 | 41 | dberr_t fil_temp_update_encryption(fil_space_t *space) { | |
| 9547 | /* Make sure the keyring is loaded. */ | ||
| 9548 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 38 times.
|
41 | if (!Encryption::check_keyring()) { |
| 9549 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
6 | ib::error() << "Can't set temporary tablespace" |
| 9550 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | << " to be encrypted because" |
| 9551 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | << " keyring plugin is not" |
| 9552 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | << " available."; |
| 9553 | 3 | return (DB_ERROR); | |
| 9554 | } | ||
| 9555 | |||
| 9556 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
|
38 | if (!fsp_enable_encryption(space)) { |
| 9557 | ✗ | ib::error() << "Can't set temporary tablespace" | |
| 9558 | ✗ | << " to be encrypted."; | |
| 9559 | ✗ | return (DB_ERROR); | |
| 9560 | } | ||
| 9561 | |||
| 9562 | const dberr_t err = | ||
| 9563 | 38 | fil_set_encryption(space->id, Encryption::AES, nullptr, nullptr); | |
| 9564 | |||
| 9565 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
|
38 | ut_ad(err == DB_SUCCESS); |
| 9566 | |||
| 9567 | 38 | return (err); | |
| 9568 | } | ||
| 9569 | |||
| 9570 | /** Reset the encryption type for the tablespace | ||
| 9571 | @param[in] space_id Space ID of tablespace for which to set | ||
| 9572 | @return DB_SUCCESS or error code */ | ||
| 9573 | 139 | dberr_t fil_reset_encryption(space_id_t space_id) { | |
| 9574 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
|
139 | ut_ad(space_id != TRX_SYS_SPACE); |
| 9575 | |||
| 9576 | 139 | auto shard = fil_system->shard_by_id(space_id); | |
| 9577 | |||
| 9578 | 139 | shard->mutex_acquire(); | |
| 9579 | |||
| 9580 | 139 | fil_space_t *space = shard->get_space_by_id(space_id); | |
| 9581 | |||
| 9582 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
|
139 | if (space == nullptr) { |
| 9583 | ✗ | shard->mutex_release(); | |
| 9584 | ✗ | return DB_NOT_FOUND; | |
| 9585 | } | ||
| 9586 | |||
| 9587 | 139 | space->m_encryption_metadata = {}; | |
| 9588 | |||
| 9589 | 139 | shard->mutex_release(); | |
| 9590 | |||
| 9591 | 139 | return DB_SUCCESS; | |
| 9592 | } | ||
| 9593 | |||
| 9594 | #ifndef UNIV_HOTBACKUP | ||
| 9595 | 256423 | bool Fil_shard::needs_encryption_rotate(fil_space_t *space) { | |
| 9596 | /* We only rotate if encryption is already set. */ | ||
| 9597 |
2/2✓ Branch 0 taken 207346 times.
✓ Branch 1 taken 49077 times.
|
256423 | if (!space->can_encrypt()) { |
| 9598 | 207346 | return false; | |
| 9599 | } | ||
| 9600 | |||
| 9601 | /* Deleted spaces do not need rotation. Their pages are being | ||
| 9602 | deleted from the buffer pool. */ | ||
| 9603 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 49077 times.
|
49077 | if (space->is_deleted()) { |
| 9604 | ✗ | return false; | |
| 9605 | } | ||
| 9606 | |||
| 9607 | /* Skip unencypted tablespaces. */ | ||
| 9608 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 49050 times.
|
49077 | if (fsp_is_system_or_temp_tablespace(space->id)) { |
| 9609 | 27 | return false; | |
| 9610 | } | ||
| 9611 | |||
| 9612 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 49046 times.
|
49050 | DBUG_EXECUTE_IF( |
| 9613 | "ib_encryption_rotate_skip", | ||
| 9614 | ib::info(ER_IB_MSG_INJECT_FAILURE, "ib_encryption_rotate_skip"); | ||
| 9615 | return false;); | ||
| 9616 | |||
| 9617 | 49046 | return true; | |
| 9618 | } | ||
| 9619 | |||
| 9620 | 716044 | size_t Fil_shard::encryption_rotate(size_t *rotate_count) { | |
| 9621 | /* If there are no tablespaces to rotate, return true. */ | ||
| 9622 | 716044 | size_t fail_count = 0; | |
| 9623 | byte encrypt_info[Encryption::INFO_SIZE]; | ||
| 9624 | using Spaces_to_rotate = std::vector<fil_space_t *>; | ||
| 9625 | 716044 | Spaces_to_rotate spaces2rotate; | |
| 9626 | |||
| 9627 | /* Use the shard mutex to collect a list of the spaces to rotate. */ | ||
| 9628 |
1/2✓ Branch 0 taken 716044 times.
✗ Branch 1 not taken.
|
716044 | mutex_acquire(); |
| 9629 | |||
| 9630 |
2/2✓ Branch 0 taken 256423 times.
✓ Branch 1 taken 716044 times.
|
972467 | for (auto &elem : m_spaces) { |
| 9631 | 256423 | auto space = elem.second; | |
| 9632 | |||
| 9633 |
3/4✓ Branch 0 taken 256423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 207377 times.
✓ Branch 3 taken 49046 times.
|
256423 | if (!needs_encryption_rotate(space)) { |
| 9634 | 207377 | continue; | |
| 9635 | } | ||
| 9636 | |||
| 9637 | /* Skip the temporary tablespace when it's in default key status, | ||
| 9638 | since it's the first server startup after bootstrap, and the | ||
| 9639 | server uuid is not ready yet. */ | ||
| 9640 |
3/6✓ Branch 0 taken 49046 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 49046 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 49046 times.
|
49046 | if (fsp_is_system_temporary(space->id) && |
| 9641 | ✗ | Encryption::get_master_key_id() == Encryption::DEFAULT_MASTER_KEY_ID) | |
| 9642 | ✗ | continue; | |
| 9643 | |||
| 9644 |
1/2✓ Branch 0 taken 49046 times.
✗ Branch 1 not taken.
|
49046 | spaces2rotate.push_back(space); |
| 9645 | } | ||
| 9646 | |||
| 9647 |
1/2✓ Branch 0 taken 716044 times.
✗ Branch 1 not taken.
|
716044 | mutex_release(); |
| 9648 | |||
| 9649 | /* We can now be assured that each fil_space_t collected above will not be | ||
| 9650 | deleted below (outside the shard mutex protection) because: | ||
| 9651 | 1. The caller, Rotate_innodb_master_key::execute(), holds an exclusive | ||
| 9652 | backup lock which blocks any other concurrent DDL or MDL on this space. | ||
| 9653 | 2. Only a thread with an MDL on the space name can mark a fil_space_t as | ||
| 9654 | deleted or actually delete it. This includes background threads like | ||
| 9655 | the purge thread doing undo truncation as well as any client DDL. | ||
| 9656 | 3. We assured above using the shard mutex that the space is not deleted. */ | ||
| 9657 | |||
| 9658 |
2/2✓ Branch 0 taken 49046 times.
✓ Branch 1 taken 716044 times.
|
765090 | for (auto &space : spaces2rotate) { |
| 9659 | /* Rotate this encrypted tablespace. */ | ||
| 9660 |
1/2✓ Branch 0 taken 49046 times.
✗ Branch 1 not taken.
|
49046 | mtr_t mtr; |
| 9661 |
1/2✓ Branch 0 taken 49046 times.
✗ Branch 1 not taken.
|
49046 | mtr_start(&mtr); |
| 9662 | 49046 | memset(encrypt_info, 0, Encryption::INFO_SIZE); | |
| 9663 |
1/2✓ Branch 0 taken 49046 times.
✗ Branch 1 not taken.
|
49046 | bool rotate_ok = fsp_header_rotate_encryption(space, encrypt_info, &mtr); |
| 9664 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 49046 times.
|
49046 | ut_ad(rotate_ok); |
| 9665 |
1/2✓ Branch 0 taken 49046 times.
✗ Branch 1 not taken.
|
49046 | mtr_commit(&mtr); |
| 9666 | |||
| 9667 |
1/2✓ Branch 0 taken 49046 times.
✗ Branch 1 not taken.
|
49046 | if (rotate_ok) { |
| 9668 | 49046 | ++(*rotate_count); | |
| 9669 | } else { | ||
| 9670 | ✗ | ++fail_count; | |
| 9671 | } | ||
| 9672 | 49046 | } | |
| 9673 | |||
| 9674 | /* This crash forces encryption rotate to complete at startup. */ | ||
| 9675 |
5/8✓ Branch 0 taken 716044 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 716040 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
|
716044 | DBUG_EXECUTE_IF( |
| 9676 | "ib_encryption_rotate_crash", | ||
| 9677 | ib::info(ER_IB_MSG_INJECT_FAILURE, "ib_encryption_rotate_crash"); | ||
| 9678 | DBUG_SUICIDE();); | ||
| 9679 | |||
| 9680 | 716040 | return fail_count; | |
| 9681 | 716040 | } | |
| 9682 | |||
| 9683 | 10534 | size_t Fil_system::encryption_rotate() { | |
| 9684 | 10534 | size_t fail_count = 0; | |
| 9685 | 10534 | size_t rotate_count = 0; | |
| 9686 | |||
| 9687 |
2/2✓ Branch 0 taken 716044 times.
✓ Branch 1 taken 10530 times.
|
726574 | for (auto shard : m_shards) { |
| 9688 |
1/2✓ Branch 0 taken 716040 times.
✗ Branch 1 not taken.
|
716044 | fail_count += shard->encryption_rotate(&rotate_count); |
| 9689 | } | ||
| 9690 | |||
| 9691 |
2/2✓ Branch 0 taken 1309 times.
✓ Branch 1 taken 9221 times.
|
10530 | if (rotate_count > 0) { |
| 9692 |
1/2✓ Branch 0 taken 1309 times.
✗ Branch 1 not taken.
|
1309 | ib::info(ER_IB_MSG_MASTER_KEY_ROTATED, static_cast<int>(rotate_count)); |
| 9693 | } | ||
| 9694 | |||
| 9695 | 10530 | return fail_count; | |
| 9696 | } | ||
| 9697 | |||
| 9698 | 9331 | void Fil_system::encryption_reencrypt( | |
| 9699 | std::vector<space_id_t> &space_id_vector) { | ||
| 9700 | /* If there are no tablespaces to reencrypt, return true. */ | ||
| 9701 |
1/2✓ Branch 0 taken 9331 times.
✗ Branch 1 not taken.
|
9331 | if (space_id_vector.empty()) { |
| 9702 | 9331 | return; | |
| 9703 | } | ||
| 9704 | |||
| 9705 | ✗ | size_t fail_count = 0; | |
| 9706 | ✗ | size_t rotate_count = 0; | |
| 9707 | byte encrypt_info[Encryption::INFO_SIZE]; | ||
| 9708 | |||
| 9709 | /* This operation is done either post recovery or when the first time | ||
| 9710 | tablespace is loaded. */ | ||
| 9711 | |||
| 9712 | ✗ | for (auto &space_id : space_id_vector) { | |
| 9713 | ✗ | fil_space_t *space = fil_space_get(space_id); | |
| 9714 | ✗ | ut_ad(space != nullptr); | |
| 9715 | ✗ | ut_ad(FSP_FLAGS_GET_ENCRYPTION(space->flags)); | |
| 9716 | |||
| 9717 | /* Rotate this encrypted tablespace. */ | ||
| 9718 | ✗ | mtr_t mtr; | |
| 9719 | ✗ | mtr_start(&mtr); | |
| 9720 | ✗ | memset(encrypt_info, 0, Encryption::INFO_SIZE); | |
| 9721 | ✗ | bool rotate_ok = fsp_header_rotate_encryption(space, encrypt_info, &mtr); | |
| 9722 | ✗ | ut_ad(rotate_ok); | |
| 9723 | ✗ | mtr_commit(&mtr); | |
| 9724 | |||
| 9725 | ✗ | if (rotate_ok) { | |
| 9726 | ✗ | ++rotate_count; | |
| 9727 | ✗ | if (fsp_is_ibd_tablespace(space_id)) { | |
| 9728 | ✗ | if (fsp_is_file_per_table(space_id, space->flags)) { | |
| 9729 | ✗ | ib::info(ER_IB_MSG_REENCRYPTED_TABLESPACE_KEY, space->name); | |
| 9730 | } else { | ||
| 9731 | ✗ | ib::info(ER_IB_MSG_REENCRYPTED_GENERAL_TABLESPACE_KEY, space->name); | |
| 9732 | } | ||
| 9733 | } | ||
| 9734 | } else { | ||
| 9735 | ✗ | ++fail_count; | |
| 9736 | } | ||
| 9737 | } | ||
| 9738 | |||
| 9739 | /* The operation should finish successfully for all tablespaces */ | ||
| 9740 | ✗ | ut_a(fail_count == 0); | |
| 9741 | } | ||
| 9742 | |||
| 9743 | 10534 | size_t fil_encryption_rotate() { return (fil_system->encryption_rotate()); } | |
| 9744 | |||
| 9745 | 9331 | void fil_encryption_reencrypt(std::vector<space_id_t> &sid_vector) { | |
| 9746 | 9331 | fil_system->encryption_reencrypt(sid_vector); | |
| 9747 | 9331 | } | |
| 9748 | |||
| 9749 | #endif /* !UNIV_HOTBACKUP */ | ||
| 9750 | |||
| 9751 | /** Constructor | ||
| 9752 | @param[in] path pathname (may also include the file basename) | ||
| 9753 | @param[in] normalize_path If false, it's the callers responsibility to | ||
| 9754 | ensure that the path is normalized. */ | ||
| 9755 | 629645 | Fil_path::Fil_path(const std::string &path, bool normalize_path) | |
| 9756 | 629645 | : m_path(path) { | |
| 9757 |
2/2✓ Branch 0 taken 21196 times.
✓ Branch 1 taken 608449 times.
|
629645 | if (normalize_path) { |
| 9758 | 21196 | normalize(m_path); | |
| 9759 | } | ||
| 9760 | |||
| 9761 |
1/2✓ Branch 0 taken 629645 times.
✗ Branch 1 not taken.
|
629645 | m_abs_path = get_real_path(m_path, false); |
| 9762 | 629645 | } | |
| 9763 | |||
| 9764 | /** Constructor | ||
| 9765 | @param[in] path Path, not necessarily NUL terminated | ||
| 9766 | @param[in] normalize_path If false, it's the callers responsibility to | ||
| 9767 | ensure that the path is normalized. */ | ||
| 9768 |
1/2✓ Branch 0 taken 19363 times.
✗ Branch 1 not taken.
|
19363 | Fil_path::Fil_path(const char *path, bool normalize_path) : m_path(path) { |
| 9769 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19363 times.
|
19363 | if (normalize_path) { |
| 9770 | ✗ | normalize(m_path); | |
| 9771 | } | ||
| 9772 | |||
| 9773 |
1/2✓ Branch 0 taken 19363 times.
✗ Branch 1 not taken.
|
19363 | m_abs_path = get_real_path(m_path, false); |
| 9774 | 19363 | } | |
| 9775 | |||
| 9776 | /** Constructor | ||
| 9777 | @param[in] path Path, not necessarily NUL terminated | ||
| 9778 | @param[in] len Length of path | ||
| 9779 | @param[in] normalize_path If false, it's the callers responsibility to | ||
| 9780 | ensure that the path is normalized. */ | ||
| 9781 | 55449 | Fil_path::Fil_path(const char *path, size_t len, bool normalize_path) | |
| 9782 |
1/2✓ Branch 0 taken 55449 times.
✗ Branch 1 not taken.
|
55449 | : m_path(path, len) { |
| 9783 |
1/2✓ Branch 0 taken 55449 times.
✗ Branch 1 not taken.
|
55449 | if (normalize_path) { |
| 9784 | 55449 | normalize(m_path); | |
| 9785 | } | ||
| 9786 | |||
| 9787 |
1/2✓ Branch 0 taken 55449 times.
✗ Branch 1 not taken.
|
55449 | m_abs_path = get_real_path(m_path, false); |
| 9788 | 55449 | } | |
| 9789 | |||
| 9790 | /** Default constructor. */ | ||
| 9791 | 20300 | Fil_path::Fil_path() : m_path(), m_abs_path() { /* No op */ | |
| 9792 | 20300 | } | |
| 9793 | |||
| 9794 | 38038 | bool Fil_path::is_same_as(const Fil_path &other) const { | |
| 9795 |
3/6✓ Branch 0 taken 38038 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 38038 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 38038 times.
|
38038 | if (path().empty() || other.path().empty()) { |
| 9796 | ✗ | return false; | |
| 9797 | } | ||
| 9798 | |||
| 9799 |
1/2✓ Branch 0 taken 38038 times.
✗ Branch 1 not taken.
|
38038 | std::string first = abs_path(); |
| 9800 |
1/2✓ Branch 0 taken 38038 times.
✗ Branch 1 not taken.
|
38038 | trim_separator(first); |
| 9801 | |||
| 9802 |
1/2✓ Branch 0 taken 38038 times.
✗ Branch 1 not taken.
|
38038 | std::string second = other.abs_path(); |
| 9803 |
1/2✓ Branch 0 taken 38038 times.
✗ Branch 1 not taken.
|
38038 | trim_separator(second); |
| 9804 | |||
| 9805 | 38038 | return (first == second); | |
| 9806 | 38038 | } | |
| 9807 | |||
| 9808 | 9623 | bool Fil_path::is_same_as(const std::string &other) const { | |
| 9809 |
3/6✓ Branch 0 taken 9623 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9623 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9623 times.
|
9623 | if (path().empty() || other.empty()) { |
| 9810 | ✗ | return false; | |
| 9811 | } | ||
| 9812 | |||
| 9813 |
1/2✓ Branch 0 taken 9623 times.
✗ Branch 1 not taken.
|
9623 | Fil_path other_path(other); |
| 9814 | |||
| 9815 |
1/2✓ Branch 0 taken 9623 times.
✗ Branch 1 not taken.
|
9623 | return is_same_as(other_path); |
| 9816 | 9623 | } | |
| 9817 | |||
| 9818 | 498 | std::pair<std::string, std::string> Fil_path::split(const std::string &path) { | |
| 9819 | 498 | const auto n = path.rfind(OS_PATH_SEPARATOR); | |
| 9820 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
|
498 | ut_ad(n != std::string::npos); |
| 9821 |
1/2✓ Branch 0 taken 498 times.
✗ Branch 1 not taken.
|
498 | return {path.substr(0, n), path.substr(n)}; |
| 9822 | } | ||
| 9823 | |||
| 9824 | 73071 | bool Fil_path::is_ancestor(const Fil_path &other) const { | |
| 9825 |
3/6✓ Branch 0 taken 73071 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 73071 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 73071 times.
|
73071 | if (path().empty() || other.path().empty()) { |
| 9826 | ✗ | return false; | |
| 9827 | } | ||
| 9828 | |||
| 9829 |
1/2✓ Branch 0 taken 73071 times.
✗ Branch 1 not taken.
|
73071 | std::string ancestor = abs_path(); |
| 9830 |
1/2✓ Branch 0 taken 73071 times.
✗ Branch 1 not taken.
|
73071 | std::string descendant = other.abs_path(); |
| 9831 | |||
| 9832 | /* We do not know if the descendant is a dir or a file. | ||
| 9833 | But the ancestor in this routine is always a directory. | ||
| 9834 | If it does not yet exist, it may not have a trailing separator. | ||
| 9835 | If there is no trailing separator, add it. */ | ||
| 9836 |
1/2✓ Branch 0 taken 73071 times.
✗ Branch 1 not taken.
|
73071 | append_separator(ancestor); |
| 9837 | |||
| 9838 |
2/2✓ Branch 0 taken 22283 times.
✓ Branch 1 taken 50788 times.
|
73071 | if (descendant.length() <= ancestor.length()) { |
| 9839 | 22283 | return false; | |
| 9840 | } | ||
| 9841 | |||
| 9842 |
1/2✓ Branch 0 taken 50788 times.
✗ Branch 1 not taken.
|
50788 | return std::equal(ancestor.begin(), ancestor.end(), descendant.begin()); |
| 9843 | 73071 | } | |
| 9844 | |||
| 9845 | 9737 | bool Fil_path::is_ancestor(const std::string &other) const { | |
| 9846 |
3/6✓ Branch 0 taken 9737 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9737 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9737 times.
|
9737 | if (path().empty() || other.empty()) { |
| 9847 | ✗ | return false; | |
| 9848 | } | ||
| 9849 | |||
| 9850 |
1/2✓ Branch 0 taken 9737 times.
✗ Branch 1 not taken.
|
9737 | Fil_path descendant(other); |
| 9851 | |||
| 9852 |
1/2✓ Branch 0 taken 9737 times.
✗ Branch 1 not taken.
|
9737 | return is_ancestor(descendant); |
| 9853 | 9737 | } | |
| 9854 | |||
| 9855 | 2886954 | bool Fil_path::is_hidden(std::string path) { | |
| 9856 |
1/2✓ Branch 0 taken 2886954 times.
✗ Branch 1 not taken.
|
2886954 | std::string basename(path); |
| 9857 |
1/2✓ Branch 0 taken 2925134 times.
✗ Branch 1 not taken.
|
2925134 | while (!basename.empty()) { |
| 9858 | 2925134 | char c = basename.back(); | |
| 9859 |
5/6✓ Branch 0 taken 2886954 times.
✓ Branch 1 taken 38180 times.
✓ Branch 2 taken 2886954 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2886954 times.
✓ Branch 5 taken 38180 times.
|
2925134 | if (!(Fil_path::is_separator(c) || c == '*')) { |
| 9860 | 2886954 | break; | |
| 9861 | } | ||
| 9862 |
1/2✓ Branch 0 taken 38180 times.
✗ Branch 1 not taken.
|
38180 | basename.resize(basename.size() - 1); |
| 9863 | } | ||
| 9864 | 2886954 | auto sep = basename.find_last_of(SEPARATOR); | |
| 9865 | |||
| 9866 |
5/6✓ Branch 0 taken 2886798 times.
✓ Branch 1 taken 156 times.
✓ Branch 2 taken 2886798 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2886796 times.
|
5773908 | return (sep != std::string::npos && basename[sep + 1] == '.'); |
| 9867 | 2886954 | } | |
| 9868 | |||
| 9869 | #ifdef _WIN32 | ||
| 9870 | bool Fil_path::is_hidden(WIN32_FIND_DATA &dirent) { | ||
| 9871 | if (dirent.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN || | ||
| 9872 | dirent.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) { | ||
| 9873 | return true; | ||
| 9874 | } | ||
| 9875 | |||
| 9876 | return false; | ||
| 9877 | } | ||
| 9878 | #endif /* WIN32 */ | ||
| 9879 | |||
| 9880 | /** @return true if the path exists and is a file . */ | ||
| 9881 | 3860860 | os_file_type_t Fil_path::get_file_type(const std::string &path) { | |
| 9882 | os_file_type_t type; | ||
| 9883 | |||
| 9884 |
1/2✓ Branch 0 taken 3860861 times.
✗ Branch 1 not taken.
|
3860860 | os_file_status(path.c_str(), nullptr, &type); |
| 9885 | |||
| 9886 | 3860861 | return type; | |
| 9887 | } | ||
| 9888 | |||
| 9889 | /** Return a string to display the file type of a path. | ||
| 9890 | @param[in] path path name | ||
| 9891 | @return true if the path exists and is a file . */ | ||
| 9892 | ✗ | const char *Fil_path::get_file_type_string(const std::string &path) { | |
| 9893 | ✗ | return get_file_type_string(Fil_path::get_file_type(path)); | |
| 9894 | } | ||
| 9895 | |||
| 9896 | /** Return a string to display the file type of a path. | ||
| 9897 | @param[in] type OS file type | ||
| 9898 | @return true if the path exists and is a file . */ | ||
| 9899 | ✗ | const char *Fil_path::get_file_type_string(os_file_type_t type) { | |
| 9900 | ✗ | switch (type) { | |
| 9901 | ✗ | case OS_FILE_TYPE_FILE: | |
| 9902 | ✗ | return "file"; | |
| 9903 | ✗ | case OS_FILE_TYPE_LINK: | |
| 9904 | ✗ | return "symbolic link"; | |
| 9905 | ✗ | case OS_FILE_TYPE_DIR: | |
| 9906 | ✗ | return "directory"; | |
| 9907 | ✗ | case OS_FILE_TYPE_BLOCK: | |
| 9908 | ✗ | return "block device"; | |
| 9909 | ✗ | case OS_FILE_TYPE_NAME_TOO_LONG: | |
| 9910 | ✗ | return "name too long"; | |
| 9911 | ✗ | case OS_FILE_PERMISSION_ERROR: | |
| 9912 | ✗ | return "permission error"; | |
| 9913 | ✗ | case OS_FILE_TYPE_MISSING: | |
| 9914 | ✗ | return "missing"; | |
| 9915 | ✗ | case OS_FILE_TYPE_UNKNOWN: | |
| 9916 | case OS_FILE_TYPE_FAILED: | ||
| 9917 | ✗ | break; | |
| 9918 | } | ||
| 9919 | ✗ | return "unknown"; | |
| 9920 | } | ||
| 9921 | |||
| 9922 | /** @return true if the path exists and is a file . */ | ||
| 9923 | ✗ | bool Fil_path::is_file_and_exists() const { | |
| 9924 | ✗ | return (get_file_type(abs_path()) == OS_FILE_TYPE_FILE); | |
| 9925 | } | ||
| 9926 | |||
| 9927 | /** @return true if the path exists and is a directory. */ | ||
| 9928 | 1364 | bool Fil_path::is_directory_and_exists() const { | |
| 9929 |
1/2✓ Branch 0 taken 1364 times.
✗ Branch 1 not taken.
|
1364 | return (get_file_type(abs_path()) == OS_FILE_TYPE_DIR); |
| 9930 | } | ||
| 9931 | |||
| 9932 | /** This validation is only for ':'. | ||
| 9933 | @return true if the path is valid. */ | ||
| 9934 | 1310 | bool Fil_path::is_valid() const { | |
| 9935 |
1/2✓ Branch 0 taken 1310 times.
✗ Branch 1 not taken.
|
1310 | auto count = std::count(m_path.begin(), m_path.end(), ':'); |
| 9936 | |||
| 9937 |
2/2✓ Branch 0 taken 1308 times.
✓ Branch 1 taken 2 times.
|
1310 | if (count == 0) { |
| 9938 | 1308 | return true; | |
| 9939 | } | ||
| 9940 | |||
| 9941 | #ifdef _WIN32 | ||
| 9942 | /* Do not allow names like "C:name.ibd" because it | ||
| 9943 | specifies the "C:" drive but allows a relative location. | ||
| 9944 | It should be like "c:\". If a single colon is used it | ||
| 9945 | must be the second byte and the third byte must be a | ||
| 9946 | separator. */ | ||
| 9947 | |||
| 9948 | /* 8 == strlen("c:\a,ibd") */ | ||
| 9949 | if (count == 1 && m_path.length() >= 8 && isalpha(m_path.at(0)) && | ||
| 9950 | m_path.at(1) == ':' && (m_path.at(2) == '\\' || m_path.at(2) == '/')) { | ||
| 9951 | return true; | ||
| 9952 | } | ||
| 9953 | #endif /* _WIN32 */ | ||
| 9954 | |||
| 9955 | 2 | return false; | |
| 9956 | } | ||
| 9957 | |||
| 9958 | 1646 | bool Fil_path::is_circular() const { | |
| 9959 | size_t first; | ||
| 9960 | |||
| 9961 | /* Find the first named directory. It is OK for a path to | ||
| 9962 | start with "../../../dir". */ | ||
| 9963 |
6/6✓ Branch 0 taken 2041 times.
✓ Branch 1 taken 413 times.
✓ Branch 2 taken 395 times.
✓ Branch 3 taken 1646 times.
✓ Branch 4 taken 808 times.
✓ Branch 5 taken 1646 times.
|
2454 | for (first = 0; m_path[first] == OS_SEPARATOR || m_path[first] == '.'; |
| 9964 | ++first) | ||
| 9965 | ; | ||
| 9966 | |||
| 9967 | 1646 | size_t back_up = m_path.find(SLASH_DOT_DOT_SLASH, first); | |
| 9968 |
2/2✓ Branch 0 taken 1637 times.
✓ Branch 1 taken 9 times.
|
1646 | if (back_up == std::string::npos) { |
| 9969 | 1637 | return false; | |
| 9970 | } | ||
| 9971 | |||
| 9972 | #ifndef _WIN32 | ||
| 9973 | /* If the path contains a symlink before the /../ and the platform | ||
| 9974 | is not Windows, then '/../' does not go bback through the symlink, | ||
| 9975 | so it is not circular. It refers to the parent of the symlinked | ||
| 9976 | location and we must allow it. On Windows, it backs up to the directory | ||
| 9977 | where the symlink starts, which is a circular reference. */ | ||
| 9978 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | std::string up_path = m_path.substr(0, back_up); |
| 9979 |
2/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
|
9 | if (my_is_symlink(up_path.c_str(), nullptr)) { |
| 9980 | ✗ | return false; | |
| 9981 | } | ||
| 9982 | #endif /* _WIN32 */ | ||
| 9983 | |||
| 9984 | 9 | return true; | |
| 9985 | 9 | } | |
| 9986 | |||
| 9987 | /** Sets the flags of the tablespace. The tablespace must be locked | ||
| 9988 | in MDL_EXCLUSIVE MODE. | ||
| 9989 | @param[in] space tablespace in-memory struct | ||
| 9990 | @param[in] flags tablespace flags */ | ||
| 9991 | 205694 | void fil_space_set_flags(fil_space_t *space, uint32_t flags) { | |
| 9992 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 205694 times.
|
205694 | ut_ad(fsp_flags_is_valid(flags)); |
| 9993 | |||
| 9994 | 205694 | rw_lock_x_lock(&space->latch, UT_LOCATION_HERE); | |
| 9995 | |||
| 9996 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 205694 times.
|
205694 | ut_a(flags < std::numeric_limits<uint32_t>::max()); |
| 9997 | 205694 | space->flags = (uint32_t)flags; | |
| 9998 | |||
| 9999 | 205694 | rw_lock_x_unlock(&space->latch); | |
| 10000 | 205694 | } | |
| 10001 | |||
| 10002 | /* Unit Tests */ | ||
| 10003 | #ifdef UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH | ||
| 10004 | #define MF Fil_path::make | ||
| 10005 | #define DISPLAY ib::info(ER_IB_MSG_342) << path | ||
| 10006 | void test_make_filepath() { | ||
| 10007 | char *path; | ||
| 10008 | const char *long_path = | ||
| 10009 | "this/is/a/very/long/path/including/a/very/" | ||
| 10010 | "looooooooooooooooooooooooooooooooooooooooooooooooo" | ||
| 10011 | "oooooooooooooooooooooooooooooooooooooooooooooooooo" | ||
| 10012 | "oooooooooooooooooooooooooooooooooooooooooooooooooo" | ||
| 10013 | "oooooooooooooooooooooooooooooooooooooooooooooooooo" | ||
| 10014 | "oooooooooooooooooooooooooooooooooooooooooooooooooo" | ||
| 10015 | "oooooooooooooooooooooooooooooooooooooooooooooooooo" | ||
| 10016 | "oooooooooooooooooooooooooooooooooooooooooooooooooo" | ||
| 10017 | "oooooooooooooooooooooooooooooooooooooooooooooooooo" | ||
| 10018 | "oooooooooooooooooooooooooooooooooooooooooooooooooo" | ||
| 10019 | "oooooooooooooooooooooooooooooooooooooooooooooooong" | ||
| 10020 | "/folder/name"; | ||
| 10021 | path = MF("/this/is/a/path/with/a/filename", nullptr, IBD, false); | ||
| 10022 | DISPLAY; | ||
| 10023 | path = MF("/this/is/a/path/with/a/filename", nullptr, ISL, false); | ||
| 10024 | DISPLAY; | ||
| 10025 | path = MF("/this/is/a/path/with/a/filename", nullptr, CFG, false); | ||
| 10026 | DISPLAY; | ||
| 10027 | path = MF("/this/is/a/path/with/a/filename", nullptr, CFP, false); | ||
| 10028 | DISPLAY; | ||
| 10029 | path = MF("/this/is/a/path/with/a/filename.ibd", nullptr, IBD, false); | ||
| 10030 | DISPLAY; | ||
| 10031 | path = MF("/this/is/a/path/with/a/filename.ibd", nullptr, IBD, false); | ||
| 10032 | DISPLAY; | ||
| 10033 | path = MF("/this/is/a/path/with/a/filename.dat", nullptr, IBD, false); | ||
| 10034 | DISPLAY; | ||
| 10035 | path = MF(nullptr, "tablespacename", NO_EXT, false); | ||
| 10036 | DISPLAY; | ||
| 10037 | path = MF(nullptr, "tablespacename", IBD, false); | ||
| 10038 | DISPLAY; | ||
| 10039 | path = MF(nullptr, "dbname/tablespacename", NO_EXT, false); | ||
| 10040 | DISPLAY; | ||
| 10041 | path = MF(nullptr, "dbname/tablespacename", IBD, false); | ||
| 10042 | DISPLAY; | ||
| 10043 | path = MF(nullptr, "dbname/tablespacename", ISL, false); | ||
| 10044 | DISPLAY; | ||
| 10045 | path = MF(nullptr, "dbname/tablespacename", CFG, false); | ||
| 10046 | DISPLAY; | ||
| 10047 | path = MF(nullptr, "dbname/tablespacename", CFP, false); | ||
| 10048 | DISPLAY; | ||
| 10049 | path = MF(nullptr, "dbname\\tablespacename", NO_EXT, false); | ||
| 10050 | DISPLAY; | ||
| 10051 | path = MF(nullptr, "dbname\\tablespacename", IBD, false); | ||
| 10052 | DISPLAY; | ||
| 10053 | path = MF("/this/is/a/path", "dbname/tablespacename", IBD, false); | ||
| 10054 | DISPLAY; | ||
| 10055 | path = MF("/this/is/a/path", "dbname/tablespacename", IBD, true); | ||
| 10056 | DISPLAY; | ||
| 10057 | path = MF("./this/is/a/path", "dbname/tablespacename.ibd", IBD, true); | ||
| 10058 | DISPLAY; | ||
| 10059 | path = MF("this\\is\\a\\path", "dbname/tablespacename", IBD, true); | ||
| 10060 | DISPLAY; | ||
| 10061 | path = MF("/this/is/a/path", "dbname\\tablespacename", IBD, true); | ||
| 10062 | DISPLAY; | ||
| 10063 | path = MF(long_path, nullptr, IBD, false); | ||
| 10064 | DISPLAY; | ||
| 10065 | path = MF(long_path, "tablespacename", IBD, false); | ||
| 10066 | DISPLAY; | ||
| 10067 | path = MF(long_path, "tablespacename", IBD, true); | ||
| 10068 | DISPLAY; | ||
| 10069 | } | ||
| 10070 | #endif /* UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH */ | ||
| 10071 | |||
| 10072 | /** Release the reserved free extents. | ||
| 10073 | @param[in] n_reserved number of reserved extents */ | ||
| 10074 | ✗ | void fil_space_t::release_free_extents(ulint n_reserved) { | |
| 10075 | #ifndef UNIV_HOTBACKUP | ||
| 10076 | ✗ | ut_ad(rw_lock_own(&latch, RW_LOCK_X)); | |
| 10077 | #endif /* !UNIV_HOTBACKUP */ | ||
| 10078 | |||
| 10079 | ✗ | ut_a(n_reserved < std::numeric_limits<uint32_t>::max()); | |
| 10080 | ✗ | ut_a(n_reserved_extents >= n_reserved); | |
| 10081 | |||
| 10082 | ✗ | n_reserved_extents -= (uint32_t)n_reserved; | |
| 10083 | } | ||
| 10084 | |||
| 10085 | #ifndef UNIV_HOTBACKUP | ||
| 10086 | |||
| 10087 | #ifdef UNIV_DEBUG | ||
| 10088 | |||
| 10089 | /** Print the extent descriptor pages of this tablespace into | ||
| 10090 | the given file. | ||
| 10091 | @param[in] filename the output file name. */ | ||
| 10092 | ✗ | void fil_space_t::print_xdes_pages(const char *filename) const { | |
| 10093 | ✗ | std::ofstream out(filename); | |
| 10094 | ✗ | print_xdes_pages(out); | |
| 10095 | } | ||
| 10096 | |||
| 10097 | /** Print the extent descriptor pages of this tablespace into | ||
| 10098 | the given output stream. | ||
| 10099 | @param[in] out the output stream. | ||
| 10100 | @return the output stream. */ | ||
| 10101 | ✗ | std::ostream &fil_space_t::print_xdes_pages(std::ostream &out) const { | |
| 10102 | ✗ | mtr_t mtr; | |
| 10103 | ✗ | const page_size_t page_size(flags); | |
| 10104 | |||
| 10105 | ✗ | mtr_start(&mtr); | |
| 10106 | |||
| 10107 | ✗ | for (page_no_t i = 0; i < 100; ++i) { | |
| 10108 | ✗ | page_no_t xdes_page_no = i * UNIV_PAGE_SIZE; | |
| 10109 | |||
| 10110 | ✗ | if (xdes_page_no >= size) { | |
| 10111 | ✗ | break; | |
| 10112 | } | ||
| 10113 | |||
| 10114 | buf_block_t *xdes_block = | ||
| 10115 | ✗ | buf_page_get(page_id_t(id, xdes_page_no), page_size, RW_S_LATCH, | |
| 10116 | UT_LOCATION_HERE, &mtr); | ||
| 10117 | |||
| 10118 | ✗ | page_t *page = buf_block_get_frame(xdes_block); | |
| 10119 | |||
| 10120 | ✗ | ulint page_type = fil_page_get_type(page); | |
| 10121 | |||
| 10122 | ✗ | switch (page_type) { | |
| 10123 | ✗ | case FIL_PAGE_TYPE_ALLOCATED: | |
| 10124 | |||
| 10125 | ✗ | ut_ad(xdes_page_no >= free_limit); | |
| 10126 | |||
| 10127 | ✗ | mtr_commit(&mtr); | |
| 10128 | ✗ | return out; | |
| 10129 | |||
| 10130 | ✗ | case FIL_PAGE_TYPE_FSP_HDR: | |
| 10131 | case FIL_PAGE_TYPE_XDES: | ||
| 10132 | ✗ | break; | |
| 10133 | ✗ | default: | |
| 10134 | ✗ | ut_error; | |
| 10135 | } | ||
| 10136 | |||
| 10137 | ✗ | xdes_page_print(out, page, xdes_page_no, &mtr); | |
| 10138 | } | ||
| 10139 | |||
| 10140 | ✗ | mtr_commit(&mtr); | |
| 10141 | ✗ | return out; | |
| 10142 | } | ||
| 10143 | #endif /* UNIV_DEBUG */ | ||
| 10144 | |||
| 10145 | /** Initialize the table space encryption | ||
| 10146 | @param[in,out] space Tablespace instance */ | ||
| 10147 | 172 | static void fil_tablespace_encryption_init(const fil_space_t *space) { | |
| 10148 |
2/2✓ Branch 0 taken 237 times.
✓ Branch 1 taken 172 times.
|
409 | for (auto &key : *recv_sys->keys) { |
| 10149 |
2/2✓ Branch 0 taken 171 times.
✓ Branch 1 taken 66 times.
|
237 | if (key.space_id != space->id) { |
| 10150 | 171 | continue; | |
| 10151 | } | ||
| 10152 | |||
| 10153 | 66 | dberr_t err = DB_SUCCESS; | |
| 10154 | |||
| 10155 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
|
66 | ut_ad(!fsp_is_system_tablespace(space->id)); |
| 10156 | |||
| 10157 |
3/4✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 42 times.
|
66 | if (fsp_is_file_per_table(space->id, space->flags)) { |
| 10158 | /* For file-per-table tablespace, which is not INPLACE algorithm, copy | ||
| 10159 | what is found on REDO Log. */ | ||
| 10160 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | err = fil_set_encryption(space->id, Encryption::AES, key.ptr, key.iv); |
| 10161 | } else { | ||
| 10162 | /* Here we try to populate space tablespace_key which is read during | ||
| 10163 | REDO scan. | ||
| 10164 | |||
| 10165 | Consider following scenario: | ||
| 10166 | 1. Alter tablespce .. encrypt=y (KEY1) | ||
| 10167 | 2. Alter tablespce .. encrypt=n | ||
| 10168 | 3. Alter tablespce .. encrypt=y (KEY2) | ||
| 10169 | |||
| 10170 | Lets say there is a crash after (3) is finished successfully. Let's say | ||
| 10171 | we scanned till REDO of (1) but couldn't reach to REDO of (3). | ||
| 10172 | |||
| 10173 | During recovery: | ||
| 10174 | ---------------- | ||
| 10175 | Case 1: | ||
| 10176 | - Before crash, pages of tablespace were encrypted with KEY2 and flushed. | ||
| 10177 | - In recovery, on REDO we've got tablespace key as KEY1. | ||
| 10178 | - Note, during tablespce load, KEY2 would have been found on page 0 and | ||
| 10179 | thus loaded already in file_space_t. | ||
| 10180 | - If we overwrite this space key (KEY2) with the one we got from REDO log | ||
| 10181 | scan (KEY1), then when we try to read a page from Disk, we will try to | ||
| 10182 | decrypt it using KEY1 whereas page was encrypted with KEY2. ERROR. | ||
| 10183 | - So don't overwrite keys on tablespace in this scenario. | ||
| 10184 | |||
| 10185 | Case 2: | ||
| 10186 | - Before crash, if tablespace pages were not flushed. | ||
| 10187 | - On disk, there may be | ||
| 10188 | - No Key (after decrypt page 0 was flushed) | ||
| 10189 | - KEY1 (after decrypt, page 0 wasn't flushed) | ||
| 10190 | - KEY2. (After 3 starts, page 0 was flushed) | ||
| 10191 | Thus tablespace would have been loaded accordingly. | ||
| 10192 | |||
| 10193 | This function is called only during recovery when a tablespce is loaded. | ||
| 10194 | So we can see the LSN for REDO Entry (recv_sys->keys) and compare it with | ||
| 10195 | the LSN of page 0 and take decision of updating encryption accordingly. */ | ||
| 10196 | |||
| 10197 |
1/2✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
|
42 | if (space->m_encryption_metadata.m_key_len == 0 || |
| 10198 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 40 times.
|
42 | key.lsn > space->m_header_page_flush_lsn) { |
| 10199 | /* Key on tablesapce isn't present or old. Update it. */ | ||
| 10200 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | err = fil_set_encryption(space->id, Encryption::AES, key.ptr, key.iv); |
| 10201 | } else { | ||
| 10202 | /* Key on tablespace is new. Skip updating. */ | ||
| 10203 | } | ||
| 10204 | } | ||
| 10205 | |||
| 10206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
|
66 | if (err != DB_SUCCESS) { |
| 10207 | ✗ | ib::error(ER_IB_MSG_343) << "Can't set encryption information" | |
| 10208 | ✗ | << " for tablespace" << space->name << "!"; | |
| 10209 | } | ||
| 10210 | |||
| 10211 | 66 | ut::free(key.iv); | |
| 10212 | 66 | ut::free(key.ptr); | |
| 10213 | |||
| 10214 | 66 | key.iv = nullptr; | |
| 10215 | 66 | key.ptr = nullptr; | |
| 10216 | |||
| 10217 | 66 | key.space_id = std::numeric_limits<space_id_t>::max(); | |
| 10218 | } | ||
| 10219 | 172 | } | |
| 10220 | |||
| 10221 | /** Modify table name in Innodb persistent stat tables, if needed. Required | ||
| 10222 | when partitioned table file names from old versions are modified to change | ||
| 10223 | the letter case. | ||
| 10224 | @param[in] old_path path to old file | ||
| 10225 | @param[in] new_path path to new file */ | ||
| 10226 | 226 | static void fil_adjust_partition_stat(const std::string &old_path, | |
| 10227 | const std::string &new_path) { | ||
| 10228 | char errstr[FN_REFLEN]; | ||
| 10229 | 226 | std::string path; | |
| 10230 | |||
| 10231 | /* Skip if not IBD file extension. */ | ||
| 10232 |
5/6✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 207 times.
✓ Branch 3 taken 19 times.
✓ Branch 4 taken 19 times.
✓ Branch 5 taken 207 times.
|
433 | if (!Fil_path::has_suffix(IBD, old_path) || |
| 10233 |
2/4✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 207 times.
|
207 | !Fil_path::has_suffix(IBD, new_path)) { |
| 10234 | 19 | return; | |
| 10235 | } | ||
| 10236 | |||
| 10237 | /* Check if partitioned table. */ | ||
| 10238 |
5/6✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 200 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 200 times.
|
407 | if (!dict_name::is_partition(old_path) || |
| 10239 |
2/4✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 200 times.
|
200 | !dict_name::is_partition(new_path)) { |
| 10240 | 7 | return; | |
| 10241 | } | ||
| 10242 | |||
| 10243 | 200 | std::string old_name; | |
| 10244 |
1/2✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
|
200 | path.assign(old_path); |
| 10245 |
2/4✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 200 times.
|
200 | if (!Fil_path::parse_file_path(path, IBD, old_name)) { |
| 10246 | ✗ | return; | |
| 10247 | } | ||
| 10248 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
|
200 | ut_ad(!old_name.empty()); |
| 10249 | |||
| 10250 | 200 | std::string new_name; | |
| 10251 |
1/2✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
|
200 | path.assign(new_path); |
| 10252 |
2/4✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 200 times.
|
200 | if (!Fil_path::parse_file_path(path, IBD, new_name)) { |
| 10253 | ✗ | return; | |
| 10254 | } | ||
| 10255 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
|
200 | ut_ad(!new_name.empty()); |
| 10256 | |||
| 10257 | /* Required for case insensitive file system where file path letter case | ||
| 10258 | doesn't matter. We need to keep the name in stat table consistent. */ | ||
| 10259 |
1/2✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
|
200 | dict_name::rebuild(new_name); |
| 10260 | |||
| 10261 |
3/4✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121 times.
✓ Branch 3 taken 79 times.
|
200 | if (old_name.compare(new_name) != 0) { |
| 10262 |
1/2✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
|
121 | dict_stats_rename_table(old_name.c_str(), new_name.c_str(), errstr, |
| 10263 | sizeof(errstr)); | ||
| 10264 | } | ||
| 10265 |
4/6✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 200 times.
✓ Branch 5 taken 26 times.
|
226 | } |
| 10266 | |||
| 10267 | /** Update the DD if any files were moved to a new location. | ||
| 10268 | Free the Tablespace_files instance. | ||
| 10269 | @param[in] read_only_mode true if InnoDB is started in read only mode. | ||
| 10270 | @return DB_SUCCESS if all OK */ | ||
| 10271 | 9614 | dberr_t Fil_system::prepare_open_for_business(bool read_only_mode) { | |
| 10272 |
4/6✓ Branch 0 taken 41 times.
✓ Branch 1 taken 9573 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 41 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9614 times.
|
9614 | if (read_only_mode && !m_moved.empty()) { |
| 10273 | ✗ | ib::error(ER_IB_MSG_344) | |
| 10274 | ✗ | << m_moved.size() << " files have been relocated" | |
| 10275 | ✗ | << " and the server has been started in read" | |
| 10276 | ✗ | << " only mode. Cannot update the data dictionary."; | |
| 10277 | |||
| 10278 | ✗ | return DB_READ_ONLY; | |
| 10279 | } | ||
| 10280 | |||
| 10281 |
2/4✓ Branch 0 taken 9614 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9614 times.
✗ Branch 3 not taken.
|
9614 | trx_t *trx = check_trx_exists(current_thd); |
| 10282 | |||
| 10283 |
1/2✓ Branch 0 taken 9614 times.
✗ Branch 1 not taken.
|
9614 | TrxInInnoDB trx_in_innodb(trx); |
| 10284 | |||
| 10285 | /* The transaction should not be active yet, start it */ | ||
| 10286 | |||
| 10287 | 9614 | trx->isolation_level = trx_t::READ_UNCOMMITTED; | |
| 10288 | |||
| 10289 |
1/2✓ Branch 0 taken 9614 times.
✗ Branch 1 not taken.
|
9614 | trx_start_if_not_started_xa(trx, false, UT_LOCATION_HERE); |
| 10290 | |||
| 10291 | 9614 | size_t count = 0; | |
| 10292 | 9614 | size_t failed = 0; | |
| 10293 | 9614 | size_t batch_size = 0; | |
| 10294 | 9614 | bool print_msg = false; | |
| 10295 | 9614 | auto start_time = std::chrono::steady_clock::now(); | |
| 10296 | |||
| 10297 | /* If some file paths have changed then update the DD */ | ||
| 10298 |
2/2✓ Branch 0 taken 226 times.
✓ Branch 1 taken 9614 times.
|
9840 | for (auto &tablespace : m_moved) { |
| 10299 | dberr_t err; | ||
| 10300 | |||
| 10301 |
1/2✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
|
226 | auto old_path = std::get<dd_fil::OLD_PATH>(tablespace); |
| 10302 | |||
| 10303 |
1/2✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
|
226 | auto space_name = std::get<dd_fil::SPACE_NAME>(tablespace); |
| 10304 | |||
| 10305 |
1/2✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
|
226 | auto new_path = std::get<dd_fil::NEW_PATH>(tablespace); |
| 10306 | 226 | auto object_id = std::get<dd_fil::OBJECT_ID>(tablespace); | |
| 10307 | |||
| 10308 | /* We already have the space name in system cs. */ | ||
| 10309 |
1/2✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
|
226 | err = dd_tablespace_rename(object_id, true, space_name.c_str(), |
| 10310 | new_path.c_str()); | ||
| 10311 | |||
| 10312 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 226 times.
|
226 | if (err != DB_SUCCESS) { |
| 10313 | ✗ | ib::error(ER_IB_MSG_345) << "Unable to update tablespace ID" | |
| 10314 | ✗ | << " " << object_id << " " | |
| 10315 | ✗ | << " '" << old_path << "' to" | |
| 10316 | ✗ | << " '" << new_path << "'"; | |
| 10317 | |||
| 10318 | ✗ | ++failed; | |
| 10319 | } | ||
| 10320 | |||
| 10321 | /* Update persistent stat table if table name is modified. */ | ||
| 10322 |
1/2✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
|
226 | fil_adjust_partition_stat(old_path, new_path); |
| 10323 | |||
| 10324 | 226 | ++count; | |
| 10325 | |||
| 10326 |
3/6✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 226 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 226 times.
|
226 | if (std::chrono::steady_clock::now() - start_time >= PRINT_INTERVAL) { |
| 10327 | ✗ | ib::info(ER_IB_MSG_346) << "Processed " << count << "/" << m_moved.size() | |
| 10328 | ✗ | << " tablespace paths. Failures " << failed; | |
| 10329 | |||
| 10330 | ✗ | start_time = std::chrono::steady_clock::now(); | |
| 10331 | ✗ | print_msg = true; | |
| 10332 | } | ||
| 10333 | |||
| 10334 | 226 | ++batch_size; | |
| 10335 | |||
| 10336 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 226 times.
|
226 | if (batch_size > 10000) { |
| 10337 | ✗ | innobase_commit_low(trx); | |
| 10338 | |||
| 10339 | ✗ | ib::info(ER_IB_MSG_347) << "Committed : " << batch_size; | |
| 10340 | |||
| 10341 | ✗ | batch_size = 0; | |
| 10342 | |||
| 10343 | ✗ | trx_start_if_not_started_xa(trx, false, UT_LOCATION_HERE); | |
| 10344 | } | ||
| 10345 | 226 | } | |
| 10346 | |||
| 10347 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 9586 times.
|
9614 | if (batch_size > 0) { |
| 10348 |
3/6✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
28 | ib::info(ER_IB_MSG_348) << "Committed : " << batch_size; |
| 10349 | } | ||
| 10350 | |||
| 10351 |
1/2✓ Branch 0 taken 9614 times.
✗ Branch 1 not taken.
|
9614 | innobase_commit_low(trx); |
| 10352 | |||
| 10353 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9614 times.
|
9614 | if (print_msg) { |
| 10354 | ✗ | ib::info(ER_IB_MSG_349) << "Updated " << count << " tablespace paths" | |
| 10355 | ✗ | << ", failures " << failed; | |
| 10356 | } | ||
| 10357 | |||
| 10358 |
1/2✓ Branch 0 taken 9614 times.
✗ Branch 1 not taken.
|
9614 | return failed == 0 ? DB_SUCCESS : DB_ERROR; |
| 10359 | 9614 | } | |
| 10360 | |||
| 10361 | /** Free the Tablespace_files instance. | ||
| 10362 | @param[in] read_only_mode true if InnoDB is started in read only mode. | ||
| 10363 | @return DB_SUCCESS if all OK */ | ||
| 10364 | 9614 | dberr_t fil_open_for_business(bool read_only_mode) { | |
| 10365 | 9614 | return fil_system->prepare_open_for_business(read_only_mode); | |
| 10366 | } | ||
| 10367 | |||
| 10368 | /** Replay a file rename operation for ddl replay. | ||
| 10369 | @param[in] page_id Space ID and first page number in the file | ||
| 10370 | @param[in] old_name old file name | ||
| 10371 | @param[in] new_name new file name | ||
| 10372 | @return whether the operation was successfully applied (the name did not | ||
| 10373 | exist, or new_name did not exist and name was successfully renamed to | ||
| 10374 | new_name) */ | ||
| 10375 | 694 | bool fil_op_replay_rename_for_ddl(const page_id_t &page_id, | |
| 10376 | const char *old_name, const char *new_name) { | ||
| 10377 | 694 | space_id_t space_id = page_id.space(); | |
| 10378 |
1/2✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
|
694 | fil_space_t *space = fil_space_get(space_id); |
| 10379 | |||
| 10380 |
5/8✓ Branch 0 taken 15 times.
✓ Branch 1 taken 679 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 694 times.
|
694 | if (space == nullptr && !fil_system->open_for_recovery(space_id)) { |
| 10381 | ✗ | ib::info(ER_IB_MSG_350) | |
| 10382 | ✗ | << "Can not find space with space ID " << space_id | |
| 10383 | ✗ | << " when replaying the DDL log " | |
| 10384 | ✗ | << "rename from '" << old_name << "' to '" << new_name << "'"; | |
| 10385 | |||
| 10386 | ✗ | return true; | |
| 10387 | } | ||
| 10388 | |||
| 10389 |
3/6✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 694 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 694 times.
✗ Branch 5 not taken.
|
694 | return fil_op_replay_rename(page_id, old_name, new_name); |
| 10390 | } | ||
| 10391 | |||
| 10392 | /** Lookup the tablespace ID for recovery and DDL log apply. | ||
| 10393 | @param[in] space_id Tablespace ID to lookup | ||
| 10394 | @return true if the space ID is known. */ | ||
| 10395 | 18813427 | bool Fil_system::lookup_for_recovery(space_id_t space_id) { | |
| 10396 |
4/6✓ Branch 0 taken 15 times.
✓ Branch 1 taken 18813412 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18813427 times.
|
18813427 | ut_ad(recv_recovery_is_on() || Log_DDL::is_in_recovery()); |
| 10397 | |||
| 10398 | /* Single threaded code, no need to acquire mutex. */ | ||
| 10399 |
1/2✓ Branch 0 taken 18813427 times.
✗ Branch 1 not taken.
|
18813427 | const auto result = get_scanned_filename_by_space_id(space_id); |
| 10400 | |||
| 10401 |
2/2✓ Branch 0 taken 18813412 times.
✓ Branch 1 taken 15 times.
|
18813427 | if (recv_recovery_is_on()) { |
| 10402 | 18813412 | const auto &end = recv_sys->deleted.end(); | |
| 10403 |
1/2✓ Branch 0 taken 18813412 times.
✗ Branch 1 not taken.
|
18813412 | const auto &it = recv_sys->deleted.find(space_id); |
| 10404 | |||
| 10405 |
2/2✓ Branch 0 taken 1405205 times.
✓ Branch 1 taken 17408207 times.
|
18813412 | if (result.second == nullptr) { |
| 10406 | /* If it wasn't deleted after finding it on disk then | ||
| 10407 | we tag it as missing. */ | ||
| 10408 | |||
| 10409 |
2/2✓ Branch 0 taken 1405201 times.
✓ Branch 1 taken 4 times.
|
1405205 | if (it == end) { |
| 10410 |
1/2✓ Branch 0 taken 1405201 times.
✗ Branch 1 not taken.
|
1405201 | recv_sys->missing_ids.insert(space_id); |
| 10411 | } | ||
| 10412 | |||
| 10413 | 1405205 | return false; | |
| 10414 | } | ||
| 10415 | |||
| 10416 | /* Check that it wasn't deleted. */ | ||
| 10417 | |||
| 10418 | 17408207 | return (it == end); | |
| 10419 | } | ||
| 10420 | |||
| 10421 | 15 | return (result.second != nullptr); | |
| 10422 | 18813427 | } | |
| 10423 | |||
| 10424 | /** Lookup the tablespace ID. | ||
| 10425 | @param[in] space_id Tablespace ID to lookup | ||
| 10426 | @return true if the space ID is known. */ | ||
| 10427 | 18797290 | bool fil_tablespace_lookup_for_recovery(space_id_t space_id) { | |
| 10428 | 18797290 | return fil_system->lookup_for_recovery(space_id); | |
| 10429 | } | ||
| 10430 | |||
| 10431 | 16137 | dberr_t Fil_system::open_for_recovery(space_id_t space_id) { | |
| 10432 |
4/6✓ Branch 0 taken 15 times.
✓ Branch 1 taken 16122 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16137 times.
|
16137 | ut_ad(recv_recovery_is_on() || Log_DDL::is_in_recovery()); |
| 10433 | |||
| 10434 |
3/4✓ Branch 0 taken 16137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 16131 times.
|
16137 | if (!lookup_for_recovery(space_id)) { |
| 10435 | 6 | return DB_FAIL; | |
| 10436 | } | ||
| 10437 | |||
| 10438 |
1/2✓ Branch 0 taken 16131 times.
✗ Branch 1 not taken.
|
16131 | const auto result = get_scanned_filename_by_space_id(space_id); |
| 10439 | |||
| 10440 | /* Duplicates should have been sorted out before start of recovery. */ | ||
| 10441 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16131 times.
|
16131 | ut_a(result.second->size() == 1); |
| 10442 | |||
| 10443 | 16131 | const auto &filename = result.second->front(); | |
| 10444 |
1/2✓ Branch 0 taken 16131 times.
✗ Branch 1 not taken.
|
16131 | const std::string path = result.first + filename; |
| 10445 | |||
| 10446 | fil_space_t *space; | ||
| 10447 | |||
| 10448 |
1/2✓ Branch 0 taken 16131 times.
✗ Branch 1 not taken.
|
16131 | auto status = ibd_open_for_recovery(space_id, path, space); |
| 10449 | |||
| 10450 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16131 times.
|
16131 | if (status == FIL_LOAD_DBWLR_CORRUPTION) { |
| 10451 | ✗ | return DB_CORRUPTION; | |
| 10452 | } | ||
| 10453 | |||
| 10454 | 16131 | dberr_t err = DB_SUCCESS; | |
| 10455 | |||
| 10456 |
2/2✓ Branch 0 taken 16117 times.
✓ Branch 1 taken 14 times.
|
16131 | if (status == FIL_LOAD_OK) { |
| 10457 | 16117 | if ((FSP_FLAGS_GET_ENCRYPTION(space->flags) || | |
| 10458 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15020 times.
|
15020 | space->encryption_op_in_progress == |
| 10459 |
4/4✓ Branch 0 taken 15020 times.
✓ Branch 1 taken 1097 times.
✓ Branch 2 taken 172 times.
✓ Branch 3 taken 15945 times.
|
32234 | Encryption::Progress::ENCRYPTION) && |
| 10460 |
2/2✓ Branch 0 taken 172 times.
✓ Branch 1 taken 925 times.
|
1097 | recv_sys->keys != nullptr) { |
| 10461 |
1/2✓ Branch 0 taken 172 times.
✗ Branch 1 not taken.
|
172 | fil_tablespace_encryption_init(space); |
| 10462 | } | ||
| 10463 | |||
| 10464 |
1/2✓ Branch 0 taken 16117 times.
✗ Branch 1 not taken.
|
16117 | if (!recv_sys->dblwr->empty()) { |
| 10465 | 16117 | err = recv_sys->dblwr->recover(space); | |
| 10466 | |||
| 10467 | } else { | ||
| 10468 | ✗ | ib::info(ER_IB_MSG_DBLWR_1317) << "DBLWR recovery skipped for " | |
| 10469 | ✗ | << space->name << " ID: " << space->id; | |
| 10470 | } | ||
| 10471 | |||
| 10472 | 16117 | return err; | |
| 10473 | } | ||
| 10474 | |||
| 10475 | 14 | return DB_FAIL; | |
| 10476 | 16131 | } | |
| 10477 | |||
| 10478 | 16122 | dberr_t fil_tablespace_open_for_recovery(space_id_t space_id) { | |
| 10479 | 16122 | return fil_system->open_for_recovery(space_id); | |
| 10480 | } | ||
| 10481 | |||
| 10482 | 72421 | Fil_state fil_tablespace_path_equals(space_id_t space_id, | |
| 10483 | const char *space_name, ulint fsp_flags, | ||
| 10484 | std::string old_path, | ||
| 10485 | std::string *new_path) { | ||
| 10486 |
8/14✓ Branch 0 taken 72421 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 53493 times.
✓ Branch 3 taken 18928 times.
✓ Branch 4 taken 53493 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 53493 times.
✓ Branch 8 taken 18928 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 18928 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 72421 times.
|
72421 | ut_ad((fsp_is_ibd_tablespace(space_id) && |
| 10487 | Fil_path::has_suffix(IBD, old_path)) || | ||
| 10488 | fsp_is_undo_tablespace(space_id)); | ||
| 10489 | |||
| 10490 | /* Watch out for implicit undo tablespaces that are created during startup. | ||
| 10491 | They will not be in the list of scanned files. But the DD might need to be | ||
| 10492 | updated if the undo directory is different now from when the database was | ||
| 10493 | initialized. The DD will be updated if we put it in fil_system->moved. */ | ||
| 10494 |
3/4✓ Branch 0 taken 72421 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18928 times.
✓ Branch 3 taken 53493 times.
|
72421 | if (fsp_is_undo_tablespace(space_id)) { |
| 10495 |
1/2✓ Branch 0 taken 18928 times.
✗ Branch 1 not taken.
|
18928 | undo::spaces->s_lock(); |
| 10496 | 18928 | space_id_t space_num = undo::id2num(space_id); | |
| 10497 |
1/2✓ Branch 0 taken 18928 times.
✗ Branch 1 not taken.
|
18928 | undo::Tablespace *undo_space = undo::spaces->find(space_num); |
| 10498 | |||
| 10499 |
6/6✓ Branch 0 taken 18925 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 18903 times.
✓ Branch 4 taken 22 times.
✓ Branch 5 taken 18906 times.
|
18928 | if (undo_space != nullptr && undo_space->is_new()) { |
| 10500 |
2/4✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
|
22 | *new_path = undo_space->file_name(); |
| 10501 |
3/4✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 4 times.
|
22 | Fil_state state = ((old_path.compare(*new_path) == 0) ? Fil_state::MATCHES |
| 10502 | 22 | : Fil_state::MOVED); | |
| 10503 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | undo::spaces->s_unlock(); |
| 10504 | 22 | return state; | |
| 10505 | } | ||
| 10506 |
1/2✓ Branch 0 taken 18906 times.
✗ Branch 1 not taken.
|
18906 | undo::spaces->s_unlock(); |
| 10507 | } | ||
| 10508 | |||
| 10509 | /* Single threaded code, no need to acquire mutex. */ | ||
| 10510 | 72399 | const auto &end = recv_sys->deleted.end(); | |
| 10511 |
1/2✓ Branch 0 taken 72399 times.
✗ Branch 1 not taken.
|
72399 | const auto &it = recv_sys->deleted.find(space_id); |
| 10512 |
1/2✓ Branch 0 taken 72399 times.
✗ Branch 1 not taken.
|
72399 | const auto result = fil_system->get_scanned_filename_by_space_id(space_id); |
| 10513 | |||
| 10514 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 72358 times.
|
72399 | if (result.second == nullptr) { |
| 10515 | /* The file was not scanned but the DD has the tablespace. Either; | ||
| 10516 | 1. This file is missing | ||
| 10517 | 2. The file could not be opened because of encryption or something else, | ||
| 10518 | 3. The path is not included in --innodb-directories. | ||
| 10519 | We need to check if the DD path is valid before we tag the file | ||
| 10520 | as missing. */ | ||
| 10521 | |||
| 10522 |
3/4✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 21 times.
|
41 | if (Fil_path::get_file_type(old_path) == OS_FILE_TYPE_FILE) { |
| 10523 | /* This file from the DD exists where the DD thinks it is. It will be | ||
| 10524 | opened later. Make some noise if the location is unknown. */ | ||
| 10525 |
2/4✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
|
20 | if (!fil_path_is_known(old_path)) { |
| 10526 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | ib::warn(ER_IB_MSG_UNPROTECTED_LOCATION_ALLOWED, old_path.c_str(), |
| 10527 | space_name); | ||
| 10528 | } | ||
| 10529 | 20 | return Fil_state::MATCHES; | |
| 10530 | } | ||
| 10531 | |||
| 10532 | /* If it wasn't deleted during redo apply, we tag it as missing. */ | ||
| 10533 | |||
| 10534 |
3/6✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 21 times.
|
21 | if (it == end && recv_recovery_is_on()) { |
| 10535 | ✗ | recv_sys->missing_ids.insert(space_id); | |
| 10536 | } | ||
| 10537 | |||
| 10538 | 21 | return Fil_state::MISSING; | |
| 10539 | } | ||
| 10540 | |||
| 10541 | /* Check if it was deleted according to the redo log. */ | ||
| 10542 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 72358 times.
|
72358 | if (it != end) { |
| 10543 | ✗ | return Fil_state::DELETED; | |
| 10544 | } | ||
| 10545 | |||
| 10546 | /* A file with this space_id was found during scanning. | ||
| 10547 | Validate its location and check if it was moved from where | ||
| 10548 | the DD thinks it is. | ||
| 10549 | |||
| 10550 | Don't compare the full filename, there can be a mismatch if | ||
| 10551 | there was a DDL in progress and we will end up renaming the path | ||
| 10552 | in the DD dictionary. Such renames should be handled by the | ||
| 10553 | atomic DDL "ddl_log". */ | ||
| 10554 | |||
| 10555 |
1/2✓ Branch 0 taken 72358 times.
✗ Branch 1 not taken.
|
72358 | std::string old_dir{old_path}; |
| 10556 | |||
| 10557 | /* Ignore the filename component of the old path. */ | ||
| 10558 | 72358 | auto pos = old_dir.find_last_of(Fil_path::SEPARATOR); | |
| 10559 |
2/2✓ Branch 0 taken 10067 times.
✓ Branch 1 taken 62291 times.
|
72358 | if (pos == std::string::npos) { |
| 10560 |
1/2✓ Branch 0 taken 10067 times.
✗ Branch 1 not taken.
|
10067 | old_dir = MySQL_datadir_path; |
| 10561 | } else { | ||
| 10562 |
1/2✓ Branch 0 taken 62291 times.
✗ Branch 1 not taken.
|
62291 | old_dir.resize(pos + 1); |
| 10563 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 62291 times.
|
62291 | ut_ad(Fil_path::is_separator(old_dir.back())); |
| 10564 | } | ||
| 10565 |
1/2✓ Branch 0 taken 72358 times.
✗ Branch 1 not taken.
|
72358 | old_dir = Fil_path::get_real_path(old_dir); |
| 10566 | |||
| 10567 | /* Build the new path from the scan path and the found path. */ | ||
| 10568 |
1/2✓ Branch 0 taken 72358 times.
✗ Branch 1 not taken.
|
72358 | std::string new_dir{result.first}; |
| 10569 | |||
| 10570 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 72358 times.
|
72358 | ut_ad(Fil_path::is_separator(new_dir.back())); |
| 10571 | |||
| 10572 |
1/2✓ Branch 0 taken 72358 times.
✗ Branch 1 not taken.
|
72358 | new_dir.append(result.second->front()); |
| 10573 | |||
| 10574 |
1/2✓ Branch 0 taken 72358 times.
✗ Branch 1 not taken.
|
72358 | new_dir = Fil_path::get_real_path(new_dir); |
| 10575 | |||
| 10576 | /* Do not use a datafile that is in the wrong place. */ | ||
| 10577 |
3/4✓ Branch 0 taken 72358 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 198 times.
✓ Branch 3 taken 72160 times.
|
72358 | if (!Fil_path::is_valid_location(space_name, space_id, fsp_flags, new_dir)) { |
| 10578 | 198 | return Fil_state::MISSING; | |
| 10579 | } | ||
| 10580 | |||
| 10581 | /* Ignore the filename component of the new path. */ | ||
| 10582 | 72160 | pos = new_dir.find_last_of(Fil_path::SEPARATOR); | |
| 10583 | |||
| 10584 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 72160 times.
|
72160 | ut_ad(pos != std::string::npos); |
| 10585 | |||
| 10586 |
1/2✓ Branch 0 taken 72160 times.
✗ Branch 1 not taken.
|
72160 | new_dir.resize(pos + 1); |
| 10587 | |||
| 10588 |
3/4✓ Branch 0 taken 72160 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 87 times.
✓ Branch 3 taken 72073 times.
|
72160 | if (old_dir.compare(new_dir) != 0) { |
| 10589 |
1/2✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
|
87 | *new_path = result.first + result.second->front(); |
| 10590 | 87 | return Fil_state::MOVED; | |
| 10591 | } | ||
| 10592 | |||
| 10593 |
1/2✓ Branch 0 taken 72073 times.
✗ Branch 1 not taken.
|
72073 | *new_path = old_path; |
| 10594 | 72073 | return Fil_state::MATCHES; | |
| 10595 | 72399 | } | |
| 10596 | |||
| 10597 | 226 | void fil_add_moved_space(dd::Object_id dd_object_id, space_id_t space_id, | |
| 10598 | const char *space_name, const std::string &old_path, | ||
| 10599 | const std::string &new_path) { | ||
| 10600 | /* Keep space_name in system cs. We handle it while modifying DD. */ | ||
| 10601 | 226 | fil_system->moved(dd_object_id, space_id, space_name, old_path, new_path); | |
| 10602 | 226 | } | |
| 10603 | |||
| 10604 | 273774 | bool fil_update_partition_name(space_id_t space_id, uint32_t fsp_flags, | |
| 10605 | bool update_space, std::string &space_name, | ||
| 10606 | std::string &dd_path) { | ||
| 10607 | #ifdef _WIN32 | ||
| 10608 | /* Safe check. Never needed on Windows for path. */ | ||
| 10609 | if (!update_space) { | ||
| 10610 | return false; | ||
| 10611 | } | ||
| 10612 | #endif /* WIN32 */ | ||
| 10613 | |||
| 10614 | /* Never needed in case insensitive file system for path. */ | ||
| 10615 |
3/4✓ Branch 0 taken 192793 times.
✓ Branch 1 taken 80981 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 192793 times.
|
273774 | if (!update_space && lower_case_file_system) { |
| 10616 | ✗ | return false; | |
| 10617 | } | ||
| 10618 | |||
| 10619 | /* Only needed for file per table. */ | ||
| 10620 |
7/8✓ Branch 0 taken 80981 times.
✓ Branch 1 taken 192793 times.
✓ Branch 2 taken 80981 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28763 times.
✓ Branch 5 taken 52218 times.
✓ Branch 6 taken 28763 times.
✓ Branch 7 taken 245011 times.
|
273774 | if (update_space && !fsp_is_file_per_table(space_id, fsp_flags)) { |
| 10621 | 28763 | return false; | |
| 10622 | } | ||
| 10623 | |||
| 10624 | /* Extract dictionary name schema_name/table_name from dd path. */ | ||
| 10625 | 245011 | std::string table_name; | |
| 10626 | |||
| 10627 |
3/4✓ Branch 0 taken 245011 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1234 times.
✓ Branch 3 taken 243777 times.
|
245011 | if (!Fil_path::parse_file_path(dd_path, IBD, table_name)) { |
| 10628 | /* Not a valid file-per-table IBD path */ | ||
| 10629 | 1234 | return false; | |
| 10630 | } | ||
| 10631 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 243777 times.
|
243777 | ut_ad(!table_name.empty()); |
| 10632 | |||
| 10633 | /* Only needed for partition file. */ | ||
| 10634 |
3/4✓ Branch 0 taken 243777 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 211424 times.
✓ Branch 3 taken 32353 times.
|
243777 | if (!dict_name::is_partition(table_name)) { |
| 10635 | 211424 | return false; | |
| 10636 | } | ||
| 10637 | |||
| 10638 | /* Rebuild dictionary name to convert partition names to lower case. */ | ||
| 10639 |
1/2✓ Branch 0 taken 32353 times.
✗ Branch 1 not taken.
|
32353 | dict_name::rebuild(table_name); |
| 10640 | |||
| 10641 |
2/2✓ Branch 0 taken 4302 times.
✓ Branch 1 taken 28051 times.
|
32353 | if (update_space) { |
| 10642 | /* Rebuild space name if required. */ | ||
| 10643 |
1/2✓ Branch 0 taken 4302 times.
✗ Branch 1 not taken.
|
4302 | dict_name::rebuild_space(table_name, space_name); |
| 10644 | } | ||
| 10645 | |||
| 10646 | /* No need to update file name for lower case file system. */ | ||
| 10647 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32353 times.
|
32353 | if (lower_case_file_system) { |
| 10648 | ✗ | return false; | |
| 10649 | } | ||
| 10650 | |||
| 10651 | /* Rebuild path and compare. */ | ||
| 10652 |
1/2✓ Branch 0 taken 32353 times.
✗ Branch 1 not taken.
|
32353 | std::string table_path = Fil_path::make_new_path(dd_path, table_name, IBD); |
| 10653 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32353 times.
|
32353 | ut_ad(!table_path.empty()); |
| 10654 | |||
| 10655 |
3/4✓ Branch 0 taken 32353 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 638 times.
✓ Branch 3 taken 31715 times.
|
32353 | if (dd_path.compare(table_path) != 0) { |
| 10656 | /* Validate that the file exists. */ | ||
| 10657 |
3/4✓ Branch 0 taken 638 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 626 times.
✓ Branch 3 taken 12 times.
|
638 | if (os_file_exists(table_path.c_str())) { |
| 10658 |
1/2✓ Branch 0 taken 626 times.
✗ Branch 1 not taken.
|
626 | dd_path.assign(table_path); |
| 10659 | 626 | return true; | |
| 10660 | |||
| 10661 | } else { | ||
| 10662 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | ib::warn(ER_IB_WARN_OPEN_PARTITION_FILE, table_path.c_str()); |
| 10663 | } | ||
| 10664 | } | ||
| 10665 | |||
| 10666 | 31727 | return false; | |
| 10667 | 245011 | } | |
| 10668 | |||
| 10669 | #endif /* !UNIV_HOTBACKUP */ | ||
| 10670 | |||
| 10671 | /** This function should be called after recovery has completed. | ||
| 10672 | Check for tablespace files for which we did not see any MLOG_FILE_DELETE | ||
| 10673 | or MLOG_FILE_RENAME record. These could not be recovered. | ||
| 10674 | @return true if there were some filenames missing for which we had to | ||
| 10675 | ignore redo log records during the apply phase */ | ||
| 10676 | 9402 | bool Fil_system::check_missing_tablespaces() { | |
| 10677 | 9402 | bool missing = false; | |
| 10678 | 9402 | const auto end = recv_sys->deleted.end(); | |
| 10679 | |||
| 10680 | /* Called in single threaded mode, no need to acquire the mutex. */ | ||
| 10681 | |||
| 10682 | 9402 | recv_sys->dblwr->check_missing_tablespaces(); | |
| 10683 | |||
| 10684 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 9402 times.
|
9407 | for (auto space_id : recv_sys->missing_ids) { |
| 10685 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (recv_sys->deleted.find(space_id) != end) { |
| 10686 | ✗ | continue; | |
| 10687 | } | ||
| 10688 | |||
| 10689 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | const auto result = get_scanned_filename_by_space_id(space_id); |
| 10690 | |||
| 10691 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if (result.second == nullptr) { |
| 10692 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (fsp_is_undo_tablespace(space_id)) { |
| 10693 | /* This could happen if an undo truncate is in progress because | ||
| 10694 | undo tablespace construction is not redo logged. The DD is updated | ||
| 10695 | at the end and may be out of sync. */ | ||
| 10696 | ✗ | continue; | |
| 10697 | } | ||
| 10698 | |||
| 10699 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
10 | ib::error(ER_IB_MSG_354) << "Could not find any file associated with" |
| 10700 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | << " the tablespace ID: " << space_id; |
| 10701 | 5 | missing = true; | |
| 10702 | |||
| 10703 | } else { | ||
| 10704 | ✗ | ut_a(!result.second->empty()); | |
| 10705 | } | ||
| 10706 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | } |
| 10707 | |||
| 10708 | 9402 | return missing; | |
| 10709 | } | ||
| 10710 | |||
| 10711 | /** This function should be called after recovery has completed. | ||
| 10712 | Check for tablespace files for which we did not see any MLOG_FILE_DELETE | ||
| 10713 | or MLOG_FILE_RENAME record. These could not be recovered | ||
| 10714 | @return true if there were some filenames missing for which we had to | ||
| 10715 | ignore redo log records during the apply phase */ | ||
| 10716 | 9402 | bool fil_check_missing_tablespaces() { | |
| 10717 | 9402 | return fil_system->check_missing_tablespaces(); | |
| 10718 | } | ||
| 10719 | |||
| 10720 | /** Redo a tablespace create. | ||
| 10721 | @param[in] ptr redo log record | ||
| 10722 | @param[in] end end of the redo log buffer | ||
| 10723 | @param[in] page_id Tablespace Id and first page in file | ||
| 10724 | @param[in] parsed_bytes Number of bytes parsed so far | ||
| 10725 | @param[in] parse_only Don't apply, parse only | ||
| 10726 | @return pointer to next redo log record | ||
| 10727 | @retval nullptr if this log record was truncated */ | ||
| 10728 | 4478 | byte *fil_tablespace_redo_create(byte *ptr, const byte *end, | |
| 10729 | const page_id_t &page_id, ulint parsed_bytes, | ||
| 10730 | bool parse_only) { | ||
| 10731 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4478 times.
|
4478 | ut_a(page_id.page_no() == 0); |
| 10732 | |||
| 10733 | /* We never recreate the system tablespace. */ | ||
| 10734 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4478 times.
|
4478 | ut_a(page_id.space() != TRX_SYS_SPACE); |
| 10735 | |||
| 10736 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4478 times.
|
4478 | ut_a(parsed_bytes != ULINT_UNDEFINED); |
| 10737 | |||
| 10738 | /* Where 6 = flags (uint32_t) + name len (uint16_t). */ | ||
| 10739 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4478 times.
|
4478 | if (end <= ptr + 6) { |
| 10740 | ✗ | return nullptr; | |
| 10741 | } | ||
| 10742 | |||
| 10743 | #ifdef UNIV_HOTBACKUP | ||
| 10744 | uint32_t flags = mach_read_from_4(ptr); | ||
| 10745 | #else | ||
| 10746 | /* Skip the flags, not used here. */ | ||
| 10747 | #endif /* UNIV_HOTBACKUP */ | ||
| 10748 | |||
| 10749 | 4478 | ptr += 4; | |
| 10750 | |||
| 10751 | 4478 | ulint len = mach_read_from_2(ptr); | |
| 10752 | |||
| 10753 | 4478 | ptr += 2; | |
| 10754 | |||
| 10755 | /* Do we have the full/valid file name. */ | ||
| 10756 |
3/4✓ Branch 0 taken 4476 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4476 times.
|
4478 | if (end < ptr + len || len < 5) { |
| 10757 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (len < 5) { |
| 10758 | char name[6]; | ||
| 10759 | |||
| 10760 | ✗ | snprintf(name, sizeof(name), "%.*s", (int)len, ptr); | |
| 10761 | |||
| 10762 | ✗ | ib::error(ER_IB_MSG_355) << "MLOG_FILE_CREATE : Invalid file name." | |
| 10763 | ✗ | << " Length (" << len << ") must be >= 5" | |
| 10764 | ✗ | << " and end in '.ibd'. File name in the" | |
| 10765 | ✗ | << " redo log is '" << name << "'"; | |
| 10766 | |||
| 10767 | ✗ | recv_sys->found_corrupt_log = true; | |
| 10768 | } | ||
| 10769 | |||
| 10770 | 2 | return nullptr; | |
| 10771 | } | ||
| 10772 | |||
| 10773 | 4476 | char *name = reinterpret_cast<char *>(ptr); | |
| 10774 | |||
| 10775 | 4476 | Fil_path::normalize(name); | |
| 10776 | |||
| 10777 | 4476 | ptr += len; | |
| 10778 | |||
| 10779 |
7/16✓ Branch 0 taken 4476 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4476 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 4449 times.
✓ Branch 6 taken 4476 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4476 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 4476 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
4503 | if (!(Fil_path::has_suffix(IBD, name) || |
| 10780 |
2/4✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
|
27 | fsp_is_undo_tablespace(page_id.space()))) { |
| 10781 | ✗ | recv_sys->found_corrupt_log = true; | |
| 10782 | |||
| 10783 | ✗ | return nullptr; | |
| 10784 | } | ||
| 10785 | |||
| 10786 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4476 times.
|
4476 | if (parse_only) { |
| 10787 | ✗ | return ptr; | |
| 10788 | } | ||
| 10789 | #ifdef UNIV_HOTBACKUP | ||
| 10790 | |||
| 10791 | meb_tablespace_redo_create(page_id, flags, name); | ||
| 10792 | |||
| 10793 | #else /* !UNIV_HOTBACKUP */ | ||
| 10794 | |||
| 10795 | /* The first condition is true during normal server operation, the | ||
| 10796 | second one during server startup after | ||
| 10797 | recv_recovery_from_checkpoint_start has completed. */ | ||
| 10798 |
3/6✓ Branch 0 taken 4476 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4476 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4476 times.
|
4476 | if (!recv_recovery_is_on() || recv_lsn_checks_on) { |
| 10799 | /* We are being called from online log tracking, file name | ||
| 10800 | processing is a no-op, and specifically do not cause any DD | ||
| 10801 | changes. */ | ||
| 10802 | ✗ | return (ptr); | |
| 10803 | } | ||
| 10804 | |||
| 10805 | const auto result = | ||
| 10806 |
1/2✓ Branch 0 taken 4476 times.
✗ Branch 1 not taken.
|
4476 | fil_system->get_scanned_filename_by_space_id(page_id.space()); |
| 10807 | |||
| 10808 |
2/2✓ Branch 0 taken 1423 times.
✓ Branch 1 taken 3053 times.
|
4476 | if (result.second == nullptr) { |
| 10809 | /* No file maps to this tablespace ID. It's possible that | ||
| 10810 | the file was deleted later or is misisng. */ | ||
| 10811 | |||
| 10812 | 1423 | return ptr; | |
| 10813 | } | ||
| 10814 | |||
| 10815 | /* Update filename with correct partition case, if needed. */ | ||
| 10816 |
1/2✓ Branch 0 taken 3053 times.
✗ Branch 1 not taken.
|
3053 | std::string name_str(name); |
| 10817 | 3053 | std::string space_name; | |
| 10818 |
1/2✓ Branch 0 taken 3053 times.
✗ Branch 1 not taken.
|
3053 | fil_update_partition_name(page_id.space(), 0, false, space_name, name_str); |
| 10819 | |||
| 10820 |
1/2✓ Branch 0 taken 3053 times.
✗ Branch 1 not taken.
|
3053 | auto abs_name = Fil_path::get_real_path(name_str); |
| 10821 | |||
| 10822 | /* Duplicates should have been sorted out before we get here. */ | ||
| 10823 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3053 times.
|
3053 | ut_a(result.second->size() == 1); |
| 10824 | |||
| 10825 | /* It's possible that the tablespace file was renamed later. */ | ||
| 10826 |
2/4✓ Branch 0 taken 3053 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3053 times.
|
3053 | if (result.second->front().compare(abs_name) == 0) { |
| 10827 | ✗ | dberr_t success = fil_tablespace_open_for_recovery(page_id.space()); | |
| 10828 | |||
| 10829 | ✗ | if (success != DB_SUCCESS) { | |
| 10830 | ✗ | ib::info(ER_IB_MSG_356) << "Create '" << abs_name << "' failed!"; | |
| 10831 | } | ||
| 10832 | } | ||
| 10833 | #endif /* UNIV_HOTBACKUP */ | ||
| 10834 | |||
| 10835 | 3053 | return ptr; | |
| 10836 | 4476 | } | |
| 10837 | |||
| 10838 | 2138 | byte *fil_tablespace_redo_rename(byte *ptr, const byte *end, | |
| 10839 | const page_id_t &page_id, ulint parsed_bytes, | ||
| 10840 | bool parse_only [[maybe_unused]]) { | ||
| 10841 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2138 times.
|
2138 | ut_a(page_id.page_no() == 0); |
| 10842 | |||
| 10843 | /* We never recreate the system tablespace. */ | ||
| 10844 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2138 times.
|
2138 | ut_a(page_id.space() != TRX_SYS_SPACE); |
| 10845 | |||
| 10846 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2138 times.
|
2138 | ut_a(parsed_bytes != ULINT_UNDEFINED); |
| 10847 | |||
| 10848 | /* Where 2 = from name len (uint16_t). */ | ||
| 10849 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2138 times.
|
2138 | if (end <= ptr + 2) { |
| 10850 | ✗ | return nullptr; | |
| 10851 | } | ||
| 10852 | |||
| 10853 | /* Read and check the RENAME FROM_NAME. */ | ||
| 10854 | 2138 | ulint from_len = mach_read_from_2(ptr); | |
| 10855 | 2138 | ptr += 2; | |
| 10856 | 2138 | char *from_name = reinterpret_cast<char *>(ptr); | |
| 10857 | |||
| 10858 | /* Check if the 'from' file name is valid. */ | ||
| 10859 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2137 times.
|
2138 | if (end < ptr + from_len) { |
| 10860 | 1 | return nullptr; | |
| 10861 | } | ||
| 10862 | |||
| 10863 | 2137 | std::string whats_wrong; | |
| 10864 | 2137 | constexpr char more_than_five[] = "The length must be >= 5."; | |
| 10865 | 2137 | constexpr char end_with_ibd[] = "The file suffix must be '.ibd'."; | |
| 10866 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2137 times.
|
2137 | if (from_len < 5) { |
| 10867 | ✗ | recv_sys->found_corrupt_log = true; | |
| 10868 | ✗ | whats_wrong.assign(more_than_five); | |
| 10869 | } else { | ||
| 10870 |
1/2✓ Branch 0 taken 2137 times.
✗ Branch 1 not taken.
|
2137 | std::string name{from_name}; |
| 10871 | |||
| 10872 |
2/4✓ Branch 0 taken 2137 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2137 times.
|
2137 | if (!Fil_path::has_suffix(IBD, name)) { |
| 10873 | ✗ | recv_sys->found_corrupt_log = true; | |
| 10874 | ✗ | whats_wrong.assign(end_with_ibd); | |
| 10875 | } | ||
| 10876 | 2137 | } | |
| 10877 | |||
| 10878 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2137 times.
|
2137 | if (recv_sys->found_corrupt_log) { |
| 10879 | ✗ | ib::info(ER_IB_MSG_357) << "MLOG_FILE_RENAME: Invalid {from} file name: '" | |
| 10880 | ✗ | << from_name << "'. " << whats_wrong; | |
| 10881 | |||
| 10882 | ✗ | return nullptr; | |
| 10883 | } | ||
| 10884 | |||
| 10885 | 2137 | ptr += from_len; | |
| 10886 | 2137 | Fil_path::normalize(from_name); | |
| 10887 | |||
| 10888 | /* Read and check the RENAME TO_NAME. */ | ||
| 10889 | 2137 | ulint to_len = mach_read_from_2(ptr); | |
| 10890 | 2137 | ptr += 2; | |
| 10891 | 2137 | char *to_name = reinterpret_cast<char *>(ptr); | |
| 10892 | |||
| 10893 | /* Check if the 'to' file name is valid. */ | ||
| 10894 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2136 times.
|
2137 | if (end < ptr + to_len) { |
| 10895 | 1 | return nullptr; | |
| 10896 | } | ||
| 10897 | |||
| 10898 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2136 times.
|
2136 | if (to_len < 5) { |
| 10899 | ✗ | recv_sys->found_corrupt_log = true; | |
| 10900 | ✗ | whats_wrong.assign(more_than_five); | |
| 10901 | } else { | ||
| 10902 |
1/2✓ Branch 0 taken 2136 times.
✗ Branch 1 not taken.
|
2136 | std::string name{to_name}; |
| 10903 | |||
| 10904 |
2/4✓ Branch 0 taken 2136 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2136 times.
|
2136 | if (!Fil_path::has_suffix(IBD, name)) { |
| 10905 | ✗ | recv_sys->found_corrupt_log = true; | |
| 10906 | ✗ | whats_wrong.assign(end_with_ibd); | |
| 10907 | } | ||
| 10908 | 2136 | } | |
| 10909 | |||
| 10910 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2136 times.
|
2136 | if (recv_sys->found_corrupt_log) { |
| 10911 | ✗ | ib::info(ER_IB_MSG_357) << "MLOG_FILE_RENAME: Invalid {to} file name: '" | |
| 10912 | ✗ | << to_name << "'. " << whats_wrong; | |
| 10913 | |||
| 10914 | ✗ | return nullptr; | |
| 10915 | } | ||
| 10916 | |||
| 10917 | 2136 | ptr += to_len; | |
| 10918 | 2136 | Fil_path::normalize(to_name); | |
| 10919 | |||
| 10920 | #ifdef UNIV_HOTBACKUP | ||
| 10921 | |||
| 10922 | if (!parse_only) { | ||
| 10923 | meb_tablespace_redo_rename(page_id, from_name, to_name); | ||
| 10924 | } | ||
| 10925 | |||
| 10926 | #else /* !UNIV_HOTBACKUP */ | ||
| 10927 | |||
| 10928 | /* Update filename with correct partition case, if needed. */ | ||
| 10929 |
1/2✓ Branch 0 taken 2136 times.
✗ Branch 1 not taken.
|
2136 | std::string to_name_str(to_name); |
| 10930 | 2136 | std::string space_name; | |
| 10931 |
1/2✓ Branch 0 taken 2136 times.
✗ Branch 1 not taken.
|
2136 | fil_update_partition_name(page_id.space(), 0, false, space_name, to_name_str); |
| 10932 | |||
| 10933 |
3/4✓ Branch 0 taken 482 times.
✓ Branch 1 taken 1654 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 482 times.
|
2136 | if (from_len == to_len && strncmp(to_name, from_name, to_len) == 0) { |
| 10934 | ✗ | ib::error(ER_IB_MSG_360) | |
| 10935 | ✗ | << "MLOG_FILE_RENAME: The from and to name are the" | |
| 10936 | ✗ | << " same: '" << from_name << "', '" << to_name << "'"; | |
| 10937 | |||
| 10938 | ✗ | recv_sys->found_corrupt_log = true; | |
| 10939 | |||
| 10940 | ✗ | return nullptr; | |
| 10941 | } | ||
| 10942 | |||
| 10943 | #endif /* UNIV_HOTBACKUP */ | ||
| 10944 | |||
| 10945 | 2136 | return ptr; | |
| 10946 | 2137 | } | |
| 10947 | |||
| 10948 | 8370 | byte *fil_tablespace_redo_extend(byte *ptr, const byte *end, | |
| 10949 | const page_id_t &page_id, ulint parsed_bytes, | ||
| 10950 | bool parse_only) { | ||
| 10951 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8370 times.
|
8370 | ut_a(page_id.page_no() == 0); |
| 10952 | |||
| 10953 | /* We never recreate the system tablespace. */ | ||
| 10954 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8370 times.
|
8370 | ut_a(page_id.space() != TRX_SYS_SPACE); |
| 10955 | |||
| 10956 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8370 times.
|
8370 | ut_a(parsed_bytes != ULINT_UNDEFINED); |
| 10957 | |||
| 10958 | /* Check for valid offset and size values */ | ||
| 10959 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8368 times.
|
8370 | if (end < ptr + 16) { |
| 10960 | 2 | return nullptr; | |
| 10961 | } | ||
| 10962 | |||
| 10963 | /* Offset within the file to start writing zeros */ | ||
| 10964 |
1/2✓ Branch 0 taken 8368 times.
✗ Branch 1 not taken.
|
8368 | os_offset_t offset = mach_read_from_8(ptr); |
| 10965 | 8368 | ptr += 8; | |
| 10966 | |||
| 10967 | /* Size of the space which needs to be initialized by | ||
| 10968 | writing zeros */ | ||
| 10969 |
1/2✓ Branch 0 taken 8368 times.
✗ Branch 1 not taken.
|
8368 | os_offset_t size = mach_read_from_8(ptr); |
| 10970 | 8368 | ptr += 8; | |
| 10971 | |||
| 10972 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8368 times.
|
8368 | if (size == 0) { |
| 10973 | ✗ | ib::error(ER_IB_MSG_INCORRECT_SIZE) | |
| 10974 | ✗ | << "MLOG_FILE_EXTEND: Incorrect value for size encountered." | |
| 10975 | ✗ | << "Redo log corruption found."; | |
| 10976 | ✗ | recv_sys->found_corrupt_log = true; | |
| 10977 | ✗ | return nullptr; | |
| 10978 | } | ||
| 10979 | |||
| 10980 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8368 times.
|
8368 | if (parse_only) { |
| 10981 | ✗ | return ptr; | |
| 10982 | } | ||
| 10983 | |||
| 10984 | #ifndef UNIV_HOTBACKUP | ||
| 10985 | const auto result = | ||
| 10986 |
1/2✓ Branch 0 taken 8368 times.
✗ Branch 1 not taken.
|
8368 | fil_system->get_scanned_filename_by_space_id(page_id.space()); |
| 10987 | |||
| 10988 |
2/2✓ Branch 0 taken 1904 times.
✓ Branch 1 taken 6464 times.
|
8368 | if (result.second == nullptr) { |
| 10989 | /* No files found for this tablespace ID. It's possible that the | ||
| 10990 | files were deleted later. */ | ||
| 10991 | 1904 | return ptr; | |
| 10992 | } | ||
| 10993 | |||
| 10994 |
1/2✓ Branch 0 taken 6464 times.
✗ Branch 1 not taken.
|
6464 | dberr_t err = fil_tablespace_open_for_recovery(page_id.space()); |
| 10995 | |||
| 10996 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6460 times.
|
6464 | if (err != DB_SUCCESS) { |
| 10997 | /* fil_tablespace_open_for_recovery may fail if the tablespace being | ||
| 10998 | opened is an undo tablespace which is also marked for truncation. | ||
| 10999 | In such a case, skip processing this redo log further and goto the | ||
| 11000 | next record without doing anything more here. */ | ||
| 11001 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
|
4 | if (fsp_is_undo_tablespace(page_id.space()) && |
| 11002 | ✗ | undo::is_active_truncate_log_present(undo::id2num(page_id.space()))) { | |
| 11003 | ✗ | return ptr; | |
| 11004 | } | ||
| 11005 | 4 | return nullptr; | |
| 11006 | } | ||
| 11007 | |||
| 11008 | /* Open the space */ | ||
| 11009 |
1/2✓ Branch 0 taken 6460 times.
✗ Branch 1 not taken.
|
6460 | bool success = fil_space_open(page_id.space()); |
| 11010 | |||
| 11011 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
|
6460 | if (!success) { |
| 11012 | ✗ | return nullptr; | |
| 11013 | } | ||
| 11014 | |||
| 11015 |
1/2✓ Branch 0 taken 6460 times.
✗ Branch 1 not taken.
|
6460 | fil_space_t *space = fil_space_get(page_id.space()); |
| 11016 | |||
| 11017 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
|
6460 | ut_a(space != nullptr); |
| 11018 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
|
6460 | ut_a(!space->files.empty()); |
| 11019 | |||
| 11020 | /* Space extension operations on temporary tablespaces | ||
| 11021 | are not redo logged as they are always recreated on | ||
| 11022 | server startup. */ | ||
| 11023 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
|
6460 | ut_a(space->purpose != FIL_TYPE_TEMPORARY); |
| 11024 | |||
| 11025 | 6460 | fil_node_t *file = &space->files.back(); | |
| 11026 | |||
| 11027 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
|
6460 | ut_a(file != nullptr); |
| 11028 | |||
| 11029 |
1/2✓ Branch 0 taken 6460 times.
✗ Branch 1 not taken.
|
6460 | page_size_t page_size(space->flags); |
| 11030 | |||
| 11031 |
1/2✓ Branch 0 taken 6460 times.
✗ Branch 1 not taken.
|
6460 | size_t phy_page_size = page_size.physical(); |
| 11032 | |||
| 11033 | /* No one else should be extending this file. */ | ||
| 11034 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
|
6460 | ut_a(!file->is_being_extended); |
| 11035 | |||
| 11036 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
|
6460 | ut_a(offset > 0); |
| 11037 |
1/2✓ Branch 0 taken 6460 times.
✗ Branch 1 not taken.
|
6460 | os_offset_t initial_fsize = os_file_get_size(file->handle); |
| 11038 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
|
6460 | ut_a(offset <= initial_fsize); |
| 11039 | /* file->size unit is FSP_EXTENT_SIZE. | ||
| 11040 | Disk-full might cause partial FSP_EXTENT_SIZE extension. */ | ||
| 11041 |
3/10✓ Branch 0 taken 6460 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 6460 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 6460 times.
|
6460 | ut_a(initial_fsize / (phy_page_size * FSP_EXTENT_SIZE) == |
| 11042 | file->size / FSP_EXTENT_SIZE); | ||
| 11043 | |||
| 11044 | /* Because punch_hole flush might recover disk-full situation. | ||
| 11045 | We might be able to extend from the partial extension at the | ||
| 11046 | previous disk-full. So, offset might not be at boundary. | ||
| 11047 | But target is aligned to the page boundary */ | ||
| 11048 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
|
6460 | ut_a(((offset + size) % phy_page_size) == 0); |
| 11049 | |||
| 11050 | /* If the physical size of the file is greater than or equal to the | ||
| 11051 | expected size (offset + size), it means that posix_fallocate was | ||
| 11052 | successfully executed. | ||
| 11053 | However, if the redo log record requests an expected size (offset + size) | ||
| 11054 | which is more than the physical size of the file, it means that | ||
| 11055 | posix_fallocate() either allocated partially (in case of emulated | ||
| 11056 | posix_fallocate) or did not allocate at all. In case posix_fallocate() | ||
| 11057 | fails, the server calls fil_write_zeros to extend the space, which | ||
| 11058 | can also fail after allocating space partially because of reasons like | ||
| 11059 | lack of disk space. The real indicator of how much file was actually | ||
| 11060 | allocated is the physical file size itself. | ||
| 11061 | Write out the 0's in the extended space only if the physical size of | ||
| 11062 | the file is less than the expected size (offset + size). */ | ||
| 11063 | |||
| 11064 | /* If the file is already equal or larger than the expected size, | ||
| 11065 | nothing more to do here. */ | ||
| 11066 |
2/2✓ Branch 0 taken 6275 times.
✓ Branch 1 taken 185 times.
|
6460 | if ((offset + size) <= initial_fsize) { |
| 11067 | 6275 | return ptr; | |
| 11068 | } | ||
| 11069 | |||
| 11070 | #if defined(UNIV_DEBUG) | ||
| 11071 | /* Validate that there are no pages in the buffer pool. */ | ||
| 11072 |
1/2✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
|
185 | buf_must_be_all_freed(); |
| 11073 | #endif /* UNIV_DEBUG */ | ||
| 11074 | |||
| 11075 | /* Adjust the actual allocation size to take care of the allocation | ||
| 11076 | problems described above. | ||
| 11077 | Find out the size by which the file should be extended to have | ||
| 11078 | a file of expected size while ensuring that the already allocated | ||
| 11079 | pages are not overwritten with zeros. */ | ||
| 11080 | 185 | os_offset_t new_ext_size = size - (initial_fsize - offset); | |
| 11081 | |||
| 11082 | /* Initialize the region starting from current end of file with zeros. */ | ||
| 11083 |
1/2✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
|
185 | err = fil_write_zeros(file, phy_page_size, initial_fsize, new_ext_size); |
| 11084 | |||
| 11085 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 185 times.
|
185 | if (err != DB_SUCCESS) { |
| 11086 | /* Error writing zeros to the file. */ | ||
| 11087 | ✗ | ib::warn(ER_IB_MSG_320) << "Error while writing " << size << " zeroes to " | |
| 11088 | ✗ | << file->name << " starting at offset " << offset; | |
| 11089 | /* Should return normally. If "return nullptr", it means "broken log" | ||
| 11090 | and will skip to apply the all of following logs. */ | ||
| 11091 | } | ||
| 11092 | |||
| 11093 | /* Get the final size of the file and adjust file->size accordingly. */ | ||
| 11094 |
1/2✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
|
185 | os_offset_t end_fsize = os_file_get_size(file->handle); |
| 11095 | |||
| 11096 | 185 | file->size = end_fsize / phy_page_size; | |
| 11097 | 185 | space->size = file->size; | |
| 11098 | |||
| 11099 |
1/2✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
|
185 | fil_flush(space->id); |
| 11100 | |||
| 11101 |
1/2✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
|
185 | fil_space_close(space->id); |
| 11102 | #endif /* !UNIV_HOTBACKUP */ | ||
| 11103 | |||
| 11104 | 185 | return ptr; | |
| 11105 | 8368 | } | |
| 11106 | |||
| 11107 | /** Redo a tablespace delete. | ||
| 11108 | @param[in] ptr redo log record | ||
| 11109 | @param[in] end end of the redo log buffer | ||
| 11110 | @param[in] page_id Tablespace Id and first page in file | ||
| 11111 | @param[in] parsed_bytes Number of bytes parsed so far | ||
| 11112 | @param[in] parse_only Don't apply, parse only | ||
| 11113 | @return pointer to next redo log record | ||
| 11114 | @retval nullptr if this log record was truncated */ | ||
| 11115 | 4101 | byte *fil_tablespace_redo_delete(byte *ptr, const byte *end, | |
| 11116 | const page_id_t &page_id, ulint parsed_bytes, | ||
| 11117 | bool parse_only) { | ||
| 11118 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4101 times.
|
4101 | ut_a(page_id.page_no() == 0); |
| 11119 | |||
| 11120 | /* We never recreate the system tablespace. */ | ||
| 11121 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4101 times.
|
4101 | ut_a(page_id.space() != TRX_SYS_SPACE); |
| 11122 | |||
| 11123 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4101 times.
|
4101 | ut_a(parsed_bytes != ULINT_UNDEFINED); |
| 11124 | |||
| 11125 | /* Where 2 = len (uint16_t). */ | ||
| 11126 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4101 times.
|
4101 | if (end <= ptr + 2) { |
| 11127 | ✗ | return nullptr; | |
| 11128 | } | ||
| 11129 | |||
| 11130 | 4101 | ulint len = mach_read_from_2(ptr); | |
| 11131 | |||
| 11132 | 4101 | ptr += 2; | |
| 11133 | |||
| 11134 | /* Do we have the full/valid file name. */ | ||
| 11135 |
2/4✓ Branch 0 taken 4101 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4101 times.
|
4101 | if (end < ptr + len || len < 5) { |
| 11136 | ✗ | if (len < 5) { | |
| 11137 | char name[6]; | ||
| 11138 | |||
| 11139 | ✗ | snprintf(name, sizeof(name), "%.*s", (int)len, ptr); | |
| 11140 | |||
| 11141 | ✗ | ib::error(ER_IB_MSG_362) << "MLOG_FILE_DELETE : Invalid file name." | |
| 11142 | ✗ | << " Length (" << len << ") must be >= 5" | |
| 11143 | ✗ | << " and end in '.ibd'. File name in the" | |
| 11144 | ✗ | << " redo log is '" << name << "'"; | |
| 11145 | } | ||
| 11146 | |||
| 11147 | ✗ | return nullptr; | |
| 11148 | } | ||
| 11149 | |||
| 11150 | 4101 | char *name = reinterpret_cast<char *>(ptr); | |
| 11151 | |||
| 11152 | 4101 | Fil_path::normalize(name); | |
| 11153 | |||
| 11154 | 4101 | ptr += len; | |
| 11155 | |||
| 11156 |
7/16✓ Branch 0 taken 4101 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4101 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 43 times.
✓ Branch 5 taken 4058 times.
✓ Branch 6 taken 4101 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4101 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 4101 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
4144 | if (!(Fil_path::has_suffix(IBD, name) || |
| 11157 |
2/4✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 43 times.
|
43 | fsp_is_undo_tablespace(page_id.space()))) { |
| 11158 | ✗ | recv_sys->found_corrupt_log = true; | |
| 11159 | |||
| 11160 | ✗ | return nullptr; | |
| 11161 | } | ||
| 11162 | |||
| 11163 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 4081 times.
|
4101 | if (parse_only) { |
| 11164 | 20 | return ptr; | |
| 11165 | } | ||
| 11166 | #ifdef UNIV_HOTBACKUP | ||
| 11167 | |||
| 11168 | meb_tablespace_redo_delete(page_id, name); | ||
| 11169 | |||
| 11170 | #else /* !UNIV_HOTBACKUP */ | ||
| 11171 | |||
| 11172 | /* The first condition is true during normal server operation, the | ||
| 11173 | second one during server startup after | ||
| 11174 | recv_recovery_from_checkpoint_start has completed. */ | ||
| 11175 |
3/6✓ Branch 0 taken 4081 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4081 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4081 times.
|
4081 | if (!recv_recovery_is_on() || recv_lsn_checks_on) { |
| 11176 | /* We are being called from online log tracking, file name | ||
| 11177 | processing is a no-op, and specifically do not cause any DD | ||
| 11178 | changes. */ | ||
| 11179 | ✗ | return (ptr); | |
| 11180 | } | ||
| 11181 | |||
| 11182 | const auto result = | ||
| 11183 |
1/2✓ Branch 0 taken 4081 times.
✗ Branch 1 not taken.
|
4081 | fil_system->get_scanned_filename_by_space_id(page_id.space()); |
| 11184 | |||
| 11185 |
1/2✓ Branch 0 taken 4081 times.
✗ Branch 1 not taken.
|
4081 | recv_sys->deleted.insert(page_id.space()); |
| 11186 |
1/2✓ Branch 0 taken 4081 times.
✗ Branch 1 not taken.
|
4081 | recv_sys->missing_ids.erase(page_id.space()); |
| 11187 | |||
| 11188 |
2/2✓ Branch 0 taken 4079 times.
✓ Branch 1 taken 2 times.
|
4081 | if (result.second == nullptr) { |
| 11189 | /* No files map to this tablespace ID. The drop must | ||
| 11190 | have succeeded. */ | ||
| 11191 | |||
| 11192 | 4079 | return ptr; | |
| 11193 | } | ||
| 11194 | |||
| 11195 | /* Space_id_set should have been sorted out before we get here. */ | ||
| 11196 | |||
| 11197 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | ut_a(result.second->size() == 1); |
| 11198 | |||
| 11199 | /* Update filename with correct partition case, if needed. */ | ||
| 11200 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | std::string name_str(name); |
| 11201 | 2 | std::string space_name; | |
| 11202 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | fil_update_partition_name(page_id.space(), 0, false, space_name, name_str); |
| 11203 | |||
| 11204 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | fil_space_free(page_id.space(), false); |
| 11205 | |||
| 11206 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | bool success = fil_system->erase_path(page_id.space()); |
| 11207 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | ut_a(success); |
| 11208 | #endif /* UNIV_HOTBACKUP */ | ||
| 11209 | |||
| 11210 | 2 | return ptr; | |
| 11211 | 4081 | } | |
| 11212 | |||
| 11213 | 105 | byte *fil_tablespace_redo_encryption(byte *ptr, const byte *end, | |
| 11214 | space_id_t space_id, lsn_t lsn) { | ||
| 11215 |
1/2✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
|
105 | fil_space_t *space = fil_space_get(space_id); |
| 11216 | |||
| 11217 | /* An undo space might be open but not have the ENCRYPTION bit set | ||
| 11218 | in its header if the current value of innodb_undo_log_encrypt=OFF | ||
| 11219 | and a crash occurred between flushing this redo record and the header | ||
| 11220 | page of the undo space. So if the flag is missing, ignore the header | ||
| 11221 | page. */ | ||
| 11222 |
5/10✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 93 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 105 times.
|
105 | if (fsp_is_undo_tablespace(space_id) && space != nullptr && |
| 11223 | ✗ | !FSP_FLAGS_GET_ENCRYPTION(space->flags)) { | |
| 11224 | ✗ | space = nullptr; | |
| 11225 | } | ||
| 11226 | |||
| 11227 | 105 | ulint offset = mach_read_from_2(ptr); | |
| 11228 | 105 | ptr += 2; | |
| 11229 | |||
| 11230 | 105 | const ulint len = mach_read_from_2(ptr); | |
| 11231 | 105 | ptr += 2; | |
| 11232 | |||
| 11233 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
|
105 | if (end < ptr + len) { |
| 11234 | ✗ | return (nullptr); | |
| 11235 | } | ||
| 11236 | |||
| 11237 |
3/6✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 105 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 105 times.
|
105 | if (offset >= UNIV_PAGE_SIZE || len + offset > UNIV_PAGE_SIZE || |
| 11238 | len != Encryption::INFO_SIZE) { | ||
| 11239 | ✗ | recv_sys->found_corrupt_log = true; | |
| 11240 | ✗ | return (nullptr); | |
| 11241 | } | ||
| 11242 | |||
| 11243 | 105 | byte *encryption_ptr = ptr; | |
| 11244 | 105 | ptr += len; | |
| 11245 | |||
| 11246 | /* If space is already loaded and have header_page_flushed_lsn greater than | ||
| 11247 | this REDO entry LSN, then skip it coz header has latest information. */ | ||
| 11248 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 103 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
105 | if (space != nullptr && space->m_header_page_flush_lsn > lsn) { |
| 11249 | 2 | return (ptr); | |
| 11250 | } | ||
| 11251 | |||
| 11252 | /* If encryption info is 0 filled, then this is erasing encryption info | ||
| 11253 | during unencryption operation. Skip decrypting it. */ | ||
| 11254 | { | ||
| 11255 | 103 | byte buf[Encryption::INFO_SIZE] = {0}; | |
| 11256 | |||
| 11257 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 85 times.
|
103 | if (memcmp(encryption_ptr + 4, buf, Encryption::INFO_SIZE - 4) == 0) { |
| 11258 | /* NOTE: We don't need to reset encryption info of space here because it | ||
| 11259 | might be needed. It will be reset when this REDO record is applied. */ | ||
| 11260 | 18 | return (ptr); | |
| 11261 | } | ||
| 11262 | } | ||
| 11263 | |||
| 11264 | 85 | byte iv[Encryption::KEY_LEN] = {0}; | |
| 11265 | 85 | byte key[Encryption::KEY_LEN] = {0}; | |
| 11266 | |||
| 11267 | 85 | Encryption_key e_key{key, iv}; | |
| 11268 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 83 times.
|
85 | if (!Encryption::decode_encryption_info(space_id, e_key, encryption_ptr, |
| 11269 | true)) { | ||
| 11270 | 2 | recv_sys->found_corrupt_log = true; | |
| 11271 | |||
| 11272 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | ib::warn(ER_IB_MSG_364) |
| 11273 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | << "Encryption information" |
| 11274 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | << " in the redo log of space " << space_id << " is invalid"; |
| 11275 | |||
| 11276 | 2 | return (nullptr); | |
| 11277 | } | ||
| 11278 | |||
| 11279 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
|
83 | ut_ad(len == Encryption::INFO_SIZE); |
| 11280 | |||
| 11281 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
|
83 | if (space != nullptr) { |
| 11282 | ✗ | Encryption::set_or_generate(Encryption::AES, key, iv, | |
| 11283 | ✗ | space->m_encryption_metadata); | |
| 11284 | ✗ | fsp_flags_set_encryption(space->flags); | |
| 11285 | ✗ | return ptr; | |
| 11286 | } | ||
| 11287 | |||
| 11288 | /* Space is not loaded yet. Remember this key in recv_sys and use it later | ||
| 11289 | to pupulate space encryption info once it is loaded. */ | ||
| 11290 |
3/4✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 79 times.
|
83 | DBUG_EXECUTE_IF("dont_update_key_found_during_REDO_scan", return ptr;); |
| 11291 | |||
| 11292 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 14 times.
|
79 | if (recv_sys->keys == nullptr) { |
| 11293 | 130 | recv_sys->keys = | |
| 11294 |
1/2✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
|
65 | ut::new_withkey<recv_sys_t::Encryption_Keys>(UT_NEW_THIS_FILE_PSI_KEY); |
| 11295 | } | ||
| 11296 | |||
| 11297 | /* Search if key entry already exists for this tablespace, update it. */ | ||
| 11298 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 73 times.
|
89 | for (auto &recv_key : *recv_sys->keys) { |
| 11299 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 10 times.
|
16 | if (recv_key.space_id == space_id) { |
| 11300 | 6 | memcpy(recv_key.iv, iv, Encryption::KEY_LEN); | |
| 11301 | 6 | memcpy(recv_key.ptr, key, Encryption::KEY_LEN); | |
| 11302 | 6 | recv_key.lsn = lsn; | |
| 11303 | 6 | return ptr; | |
| 11304 | } | ||
| 11305 | } | ||
| 11306 | |||
| 11307 | /* No existing entry found, create new one and insert it. */ | ||
| 11308 | recv_sys_t::Encryption_Key new_key; | ||
| 11309 | 73 | new_key.iv = static_cast<byte *>( | |
| 11310 | 73 | ut::malloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, Encryption::KEY_LEN)); | |
| 11311 | 73 | memcpy(new_key.iv, iv, Encryption::KEY_LEN); | |
| 11312 | 73 | new_key.ptr = static_cast<byte *>( | |
| 11313 | 73 | ut::malloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, Encryption::KEY_LEN)); | |
| 11314 | 73 | memcpy(new_key.ptr, key, Encryption::KEY_LEN); | |
| 11315 | 73 | new_key.space_id = space_id; | |
| 11316 | 73 | new_key.lsn = lsn; | |
| 11317 |
1/2✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
|
73 | recv_sys->keys->push_back(new_key); |
| 11318 | |||
| 11319 | 73 | return ptr; | |
| 11320 | } | ||
| 11321 | |||
| 11322 | ✗ | void Tablespace_dirs::warn_ignore(std::string ignore_path, const char *reason) { | |
| 11323 | ✗ | ib::warn(ER_IB_MSG_IGNORE_SCAN_PATH, ignore_path.c_str(), reason); | |
| 11324 | } | ||
| 11325 | |||
| 11326 | 19544 | void Tablespace_dirs::add_path(const std::string &path_in, bool is_undo_dir) { | |
| 11327 | /* Ignore an invalid path. */ | ||
| 11328 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19544 times.
|
19544 | if (path_in == "") { |
| 11329 | ✗ | return; | |
| 11330 | } | ||
| 11331 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19544 times.
|
19544 | if (path_in == "/") { |
| 11332 | ✗ | warn_ignore(path_in, | |
| 11333 | "the root directory '/' is not allowed to be scanned."); | ||
| 11334 | ✗ | return; | |
| 11335 | } | ||
| 11336 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19544 times.
|
19544 | if (std::string::npos != path_in.find('*')) { |
| 11337 | ✗ | warn_ignore(path_in, "it contains '*'."); | |
| 11338 | ✗ | return; | |
| 11339 | } | ||
| 11340 | |||
| 11341 | /* Assume this path is a directory and put a trailing slash on it. */ | ||
| 11342 |
1/2✓ Branch 0 taken 19544 times.
✗ Branch 1 not taken.
|
19544 | std::string dir_in(path_in); |
| 11343 |
1/2✓ Branch 0 taken 19544 times.
✗ Branch 1 not taken.
|
19544 | Fil_path::append_separator(dir_in); |
| 11344 | |||
| 11345 |
1/2✓ Branch 0 taken 19544 times.
✗ Branch 1 not taken.
|
19544 | Fil_path found_path(dir_in, true); |
| 11346 | |||
| 11347 | /* Exclude this path if it is a duplicate of a path already stored or | ||
| 11348 | if a previously stored path is an ancestor. Remove any previously stored | ||
| 11349 | path that is a descendant of this path. */ | ||
| 11350 |
2/2✓ Branch 0 taken 9981 times.
✓ Branch 1 taken 9887 times.
|
19868 | for (auto it = m_dirs.cbegin(); it != m_dirs.cend(); /* No op */) { |
| 11351 |
3/4✓ Branch 0 taken 9981 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9657 times.
✓ Branch 3 taken 324 times.
|
9981 | if (it->root().is_same_as(found_path)) { |
| 11352 | /* The exact same path is obviously ignored, so there is no need to | ||
| 11353 | log a warning. */ | ||
| 11354 | 9657 | return; | |
| 11355 | } | ||
| 11356 | |||
| 11357 | /* Check if dir_abs_path is an ancestor of this path */ | ||
| 11358 |
2/4✓ Branch 0 taken 324 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 324 times.
|
324 | if (it->root().is_ancestor(found_path)) { |
| 11359 | /* Descendant directories will be scanned recursively, so don't | ||
| 11360 | add it to the scan list. Log a warning unless this descendant | ||
| 11361 | is the undo directory since it must be supplied even if it is | ||
| 11362 | a descendant of another data location. */ | ||
| 11363 | ✗ | if (!is_undo_dir) { | |
| 11364 | ✗ | std::string reason = "it is a sub-directory of '"; | |
| 11365 | ✗ | reason += it->root().abs_path(); | |
| 11366 | ✗ | warn_ignore(path_in, reason.c_str()); | |
| 11367 | } | ||
| 11368 | ✗ | return; | |
| 11369 | } | ||
| 11370 | |||
| 11371 |
2/4✓ Branch 0 taken 324 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 324 times.
|
324 | if (found_path.is_ancestor(it->root())) { |
| 11372 | /* This path is an ancestor of an existing dir in fil_system::m_dirs. | ||
| 11373 | The settings have overlapping locations. Put a note about it to | ||
| 11374 | the error log. The undo_dir is added last, so if it is an ancestor, | ||
| 11375 | the descendant was listed as a datafile directory. So always issue | ||
| 11376 | this message*/ | ||
| 11377 | ✗ | std::string reason = "it is a sub-directory of '"; | |
| 11378 | ✗ | reason += found_path; | |
| 11379 | ✗ | warn_ignore(it->root().path(), reason.c_str()); | |
| 11380 | |||
| 11381 | /* It might also be an ancestor to another dir as well, so keep looking. | ||
| 11382 | We must delete this descendant because we know that this ancestor path | ||
| 11383 | will be inserted and all its descendants will be scanned. */ | ||
| 11384 | ✗ | it = m_dirs.erase(it); | |
| 11385 | ✗ | } else { | |
| 11386 | 324 | it++; | |
| 11387 | } | ||
| 11388 | } | ||
| 11389 | |||
| 11390 |
2/4✓ Branch 0 taken 9887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9887 times.
✗ Branch 3 not taken.
|
9887 | m_dirs.push_back(Tablespace_files{found_path.path()}); |
| 11391 | 9887 | return; | |
| 11392 | 19544 | } | |
| 11393 | |||
| 11394 | 86 | void Tablespace_dirs::add_paths(const std::string &str, | |
| 11395 | const std::string &delimiters) { | ||
| 11396 | 86 | std::string::size_type start = 0; | |
| 11397 | 86 | std::string::size_type end = 0; | |
| 11398 | |||
| 11399 | /* Scan until 'start' reaches the end of the string (npos) */ | ||
| 11400 | for (;;) { | ||
| 11401 | 197 | start = str.find_first_not_of(delimiters, end); | |
| 11402 |
2/2✓ Branch 0 taken 86 times.
✓ Branch 1 taken 111 times.
|
197 | if (std::string::npos == start) { |
| 11403 | 86 | break; | |
| 11404 | } | ||
| 11405 | |||
| 11406 | 111 | end = str.find_first_of(delimiters, start); | |
| 11407 | |||
| 11408 |
1/2✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
|
111 | const auto path = str.substr(start, end - start); |
| 11409 | |||
| 11410 |
1/2✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
|
111 | add_path(path); |
| 11411 | 111 | } | |
| 11412 | 86 | } | |
| 11413 | |||
| 11414 | /** Check whether we can rename the file | ||
| 11415 | @param[in] space Tablespace for which to rename | ||
| 11416 | @param[in] name Source file name | ||
| 11417 | @param[in] df Target file that exists on disk | ||
| 11418 | @return DB_SUCCESS if all OK */ | ||
| 11419 | 173 | static dberr_t fil_rename_validate(fil_space_t *space, const std::string &name, | |
| 11420 | Datafile &&df) { | ||
| 11421 | 173 | dberr_t err = df.validate_for_recovery(space->id).error; | |
| 11422 | /* The validate_for_recovery will set space_id, but will close the file. It is | ||
| 11423 | safe to access filepath and space_id. */ | ||
| 11424 | |||
| 11425 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
|
173 | if (err == DB_TABLESPACE_NOT_FOUND) { |
| 11426 | /* Tablespace header doesn't contain the expected | ||
| 11427 | tablespace ID. This is can happen during truncate. */ | ||
| 11428 | |||
| 11429 | ✗ | return err; | |
| 11430 | |||
| 11431 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
|
173 | } else if (err != DB_SUCCESS) { |
| 11432 | ✗ | ib::warn(ER_IB_MSG_367) << "Failed to read the first page of the" | |
| 11433 | ✗ | << " file '" << df.filepath() << "'." | |
| 11434 | ✗ | << " You will need to verify and move the" | |
| 11435 | ✗ | << " file out of the way retry recovery."; | |
| 11436 | |||
| 11437 | ✗ | return err; | |
| 11438 | } | ||
| 11439 | |||
| 11440 | 173 | auto file = &space->files.front(); | |
| 11441 | |||
| 11442 |
1/2✓ Branch 0 taken 173 times.
✗ Branch 1 not taken.
|
173 | if (strcmp(df.filepath(), file->name) == 0) { |
| 11443 | /* Check if already points to the correct file. | ||
| 11444 | Must have the same space ID */ | ||
| 11445 | |||
| 11446 |
1/2✓ Branch 0 taken 173 times.
✗ Branch 1 not taken.
|
173 | ib::info(ER_IB_MSG_368) << "Tablespace ID already maps to: '" |
| 11447 |
2/4✓ Branch 0 taken 173 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 173 times.
✗ Branch 3 not taken.
|
173 | << df.filepath() << "', rename ignored."; |
| 11448 | |||
| 11449 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
|
173 | ut_a(df.space_id() == space->id); |
| 11450 | |||
| 11451 | 173 | return DB_SUCCESS; | |
| 11452 | |||
| 11453 | ✗ | } else if (df.space_id() != space->id) { | |
| 11454 | /* Target file exists on disk but has a different | ||
| 11455 | tablespace ID. The user should manually delete it. */ | ||
| 11456 | |||
| 11457 | ✗ | ib::error(ER_IB_MSG_369) | |
| 11458 | ✗ | << "Cannot rename '" << name << "' to '" << df.filepath() << "'. File '" | |
| 11459 | ✗ | << df.filepath() << "' tablespace ID " << df.space_id() | |
| 11460 | ✗ | << " doesn't match the expected tablespace" | |
| 11461 | ✗ | << " ID " << space->id << ". You will need to verify and move '" | |
| 11462 | ✗ | << df.filepath() << "' manually and retry recovery!"; | |
| 11463 | |||
| 11464 | ✗ | return DB_ERROR; | |
| 11465 | } | ||
| 11466 | |||
| 11467 | /* Target file exists on disk and has the same ID. */ | ||
| 11468 | |||
| 11469 | ✗ | ib::error(ER_IB_MSG_370) | |
| 11470 | ✗ | << "Cannot rename '" << name << "' to '" << df.filepath() | |
| 11471 | ✗ | << "'. The File '" << df.filepath() << " already exists on" | |
| 11472 | ✗ | << " disk. You will need to verify and move either file" | |
| 11473 | ✗ | << " manually and retry recovery!"; | |
| 11474 | |||
| 11475 | ✗ | return DB_ERROR; | |
| 11476 | } | ||
| 11477 | |||
| 11478 | /** Replay a file rename operation if possible. | ||
| 11479 | @param[in] page_id Space ID and first page number in the file | ||
| 11480 | @param[in] old_name old file name | ||
| 11481 | @param[in] new_name new file name | ||
| 11482 | @return whether the operation was successfully applied (the name did not exist, | ||
| 11483 | or new_name did not exist and name was successfully renamed to new_name) */ | ||
| 11484 | 694 | static bool fil_op_replay_rename(const page_id_t &page_id, | |
| 11485 | const std::string &old_name, | ||
| 11486 | const std::string &new_name) { | ||
| 11487 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 694 times.
|
694 | ut_ad(page_id.page_no() == 0); |
| 11488 |
2/4✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 694 times.
|
694 | ut_ad(old_name.compare(new_name) != 0); |
| 11489 |
2/4✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 694 times.
|
694 | ut_ad(Fil_path::has_suffix(IBD, new_name)); |
| 11490 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 694 times.
|
694 | ut_ad(page_id.space() != TRX_SYS_SPACE); |
| 11491 | |||
| 11492 | /* In order to replay the rename, the following must hold: | ||
| 11493 | 1. The new name is not already used. | ||
| 11494 | 2. A tablespace exists with the old name. | ||
| 11495 | 3. The space ID for that tablespace matches this log entry. | ||
| 11496 | This will prevent unintended renames during recovery. */ | ||
| 11497 | |||
| 11498 | 694 | space_id_t space_id = page_id.space(); | |
| 11499 |
1/2✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
|
694 | fil_space_t *space = fil_space_get(space_id); |
| 11500 | |||
| 11501 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 694 times.
|
694 | if (space == nullptr) { |
| 11502 | ✗ | return true; | |
| 11503 | } | ||
| 11504 | |||
| 11505 |
1/2✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
|
694 | std::string name{new_name}; |
| 11506 | { | ||
| 11507 | 694 | Datafile df; | |
| 11508 | |||
| 11509 |
1/2✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
|
694 | df.set_filepath(name.c_str()); |
| 11510 | |||
| 11511 |
3/4✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 173 times.
✓ Branch 3 taken 521 times.
|
694 | if (df.open_read_only(false) == DB_SUCCESS) { |
| 11512 |
1/2✓ Branch 0 taken 173 times.
✗ Branch 1 not taken.
|
173 | dberr_t err = fil_rename_validate(space, old_name, std::move(df)); |
| 11513 | |||
| 11514 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
|
173 | if (err == DB_TABLESPACE_NOT_FOUND) { |
| 11515 | /* This can happen during truncate. */ | ||
| 11516 | ✗ | ib::info(ER_IB_MSG_371) << "Tablespace ID mismatch in '" << name << "'"; | |
| 11517 | } | ||
| 11518 | 173 | return (err == DB_SUCCESS); | |
| 11519 | } | ||
| 11520 |
2/2✓ Branch 0 taken 521 times.
✓ Branch 1 taken 173 times.
|
694 | } |
| 11521 | |||
| 11522 | 521 | auto path_sep_pos = name.find_last_of(Fil_path::SEPARATOR); | |
| 11523 | |||
| 11524 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 521 times.
|
521 | ut_a(path_sep_pos != std::string::npos); |
| 11525 | |||
| 11526 | /* Create the database directory for the new name, if | ||
| 11527 | it does not exist yet */ | ||
| 11528 | |||
| 11529 |
1/2✓ Branch 0 taken 521 times.
✗ Branch 1 not taken.
|
521 | name.resize(path_sep_pos); |
| 11530 | |||
| 11531 |
1/2✓ Branch 0 taken 521 times.
✗ Branch 1 not taken.
|
521 | bool success = os_file_create_directory(name.c_str(), false); |
| 11532 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 521 times.
|
521 | ut_a(success); |
| 11533 | |||
| 11534 | 521 | auto datadir_pos = name.find_last_of(Fil_path::SEPARATOR); | |
| 11535 | |||
| 11536 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 521 times.
|
521 | ut_ad(datadir_pos != std::string::npos); |
| 11537 | |||
| 11538 |
1/2✓ Branch 0 taken 521 times.
✗ Branch 1 not taken.
|
521 | name.erase(0, datadir_pos + 1); |
| 11539 | |||
| 11540 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 521 times.
|
521 | ut_ad(!Fil_path::is_separator(name.back())); |
| 11541 | |||
| 11542 | /* schema/table separator is always a '/'. */ | ||
| 11543 |
1/2✓ Branch 0 taken 521 times.
✗ Branch 1 not taken.
|
521 | name.push_back('/'); |
| 11544 | |||
| 11545 | /* Strip the '.ibd' suffix. */ | ||
| 11546 |
1/2✓ Branch 0 taken 521 times.
✗ Branch 1 not taken.
|
521 | name.append(new_name.begin() + path_sep_pos + 1, new_name.end() - 4); |
| 11547 | |||
| 11548 |
2/4✓ Branch 0 taken 521 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 521 times.
|
521 | ut_ad(!Fil_path::has_suffix(IBD, name)); |
| 11549 | |||
| 11550 | 521 | const auto ptr = name.c_str(); | |
| 11551 | |||
| 11552 | dberr_t err = | ||
| 11553 |
1/2✓ Branch 0 taken 521 times.
✗ Branch 1 not taken.
|
521 | fil_rename_tablespace(space_id, old_name.c_str(), ptr, new_name.c_str()); |
| 11554 | |||
| 11555 | /* Stop recovery if this does not succeed. */ | ||
| 11556 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 521 times.
|
521 | ut_a(err == DB_SUCCESS); |
| 11557 | |||
| 11558 | 521 | return true; | |
| 11559 | 694 | } | |
| 11560 | |||
| 11561 | /** Get the tablespace ID from an .ibd and/or an undo tablespace. If the ID is 0 | ||
| 11562 | on the first page then try finding the ID with Datafile::find_space_id(). | ||
| 11563 | @param[in] filename File name to check | ||
| 11564 | @return s_invalid_space_id if not found, otherwise the space ID */ | ||
| 11565 | 78701 | space_id_t Fil_system::get_tablespace_id(const std::string &filename) { | |
| 11566 |
1/2✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
|
78701 | FILE *fp = fopen(filename.c_str(), "rb"); |
| 11567 | |||
| 11568 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78701 times.
|
78701 | if (fp == nullptr) { |
| 11569 | ✗ | ib::warn(ER_IB_MSG_372) << "Unable to open '" << filename << "'"; | |
| 11570 | ✗ | return dict_sys_t::s_invalid_space_id; | |
| 11571 | } | ||
| 11572 | |||
| 11573 | 78701 | std::vector<space_id_t> space_ids; | |
| 11574 | 78701 | auto page_size = srv_page_size; | |
| 11575 | |||
| 11576 |
1/2✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
|
78701 | space_ids.reserve(MAX_PAGES_TO_READ); |
| 11577 | |||
| 11578 | 78701 | const auto n_bytes = page_size * MAX_PAGES_TO_READ; | |
| 11579 | |||
| 11580 |
1/2✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
|
78701 | std::unique_ptr<byte[]> buf(new byte[n_bytes]); |
| 11581 | |||
| 11582 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78701 times.
|
78701 | if (!buf) { |
| 11583 | ✗ | return dict_sys_t::s_invalid_space_id; | |
| 11584 | } | ||
| 11585 | |||
| 11586 |
1/2✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
|
78701 | auto pages_read = fread(buf.get(), page_size, MAX_PAGES_TO_READ, fp); |
| 11587 | |||
| 11588 |
2/4✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78701 times.
|
78701 | DBUG_EXECUTE_IF("invalid_header", pages_read = 0;); |
| 11589 | |||
| 11590 | /* Find the space id from the pages read if enough pages could be read. | ||
| 11591 | Fall back to the more heavier method of finding the space id from | ||
| 11592 | Datafile::find_space_id() if pages cannot be read properly. */ | ||
| 11593 |
2/2✓ Branch 0 taken 78678 times.
✓ Branch 1 taken 23 times.
|
78701 | if (pages_read >= MAX_PAGES_TO_READ) { |
| 11594 | 78678 | auto bytes_read = pages_read * page_size; | |
| 11595 | |||
| 11596 | #ifdef POSIX_FADV_DONTNEED | ||
| 11597 | 78678 | posix_fadvise(fileno(fp), 0, bytes_read, POSIX_FADV_DONTNEED); | |
| 11598 | #endif /* POSIX_FADV_DONTNEED */ | ||
| 11599 | |||
| 11600 |
2/2✓ Branch 0 taken 78678 times.
✓ Branch 1 taken 179 times.
|
78857 | for (page_no_t i = 0; i < MAX_PAGES_TO_READ; ++i) { |
| 11601 | 78678 | const auto off = i * page_size + FIL_PAGE_SPACE_ID; | |
| 11602 | |||
| 11603 |
1/2✓ Branch 0 taken 78678 times.
✗ Branch 1 not taken.
|
78678 | if (off == FIL_PAGE_SPACE_ID) { |
| 11604 | /* Find out the page size of the tablespace from the first page. | ||
| 11605 | In case of compressed pages, the subsequent pages can be of different | ||
| 11606 | sizes. If MAX_PAGES_TO_READ is changed to a different value, then the | ||
| 11607 | page size of subsequent pages is needed to find out the offset for | ||
| 11608 | space ID. */ | ||
| 11609 | |||
| 11610 | 78678 | auto space_flags_offset = FSP_HEADER_OFFSET + FSP_SPACE_FLAGS; | |
| 11611 | |||
| 11612 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78678 times.
|
78678 | ut_a(space_flags_offset + 4 < n_bytes); |
| 11613 | |||
| 11614 |
1/2✓ Branch 0 taken 78678 times.
✗ Branch 1 not taken.
|
78678 | const auto flags = mach_read_from_4(buf.get() + space_flags_offset); |
| 11615 | |||
| 11616 |
1/2✓ Branch 0 taken 78678 times.
✗ Branch 1 not taken.
|
78678 | page_size_t space_page_size(flags); |
| 11617 | |||
| 11618 |
1/2✓ Branch 0 taken 78678 times.
✗ Branch 1 not taken.
|
78678 | page_size = space_page_size.physical(); |
| 11619 | } | ||
| 11620 | |||
| 11621 |
2/4✓ Branch 0 taken 78678 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78678 times.
✗ Branch 3 not taken.
|
78678 | space_ids.push_back(mach_read_from_4(buf.get() + off)); |
| 11622 | |||
| 11623 |
2/2✓ Branch 0 taken 78499 times.
✓ Branch 1 taken 179 times.
|
78678 | if ((i + 1) * page_size >= bytes_read) { |
| 11624 | 78499 | break; | |
| 11625 | } | ||
| 11626 | } | ||
| 11627 | } | ||
| 11628 | |||
| 11629 |
1/2✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
|
78701 | fclose(fp); |
| 11630 | |||
| 11631 | space_id_t space_id; | ||
| 11632 | |||
| 11633 |
2/2✓ Branch 0 taken 78678 times.
✓ Branch 1 taken 23 times.
|
78701 | if (!space_ids.empty()) { |
| 11634 | 78678 | space_id = space_ids.front(); | |
| 11635 | |||
| 11636 |
2/2✓ Branch 0 taken 78678 times.
✓ Branch 1 taken 78668 times.
|
157346 | for (auto id : space_ids) { |
| 11637 |
3/4✓ Branch 0 taken 78668 times.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 78668 times.
|
78678 | if (id == 0 || space_id != id) { |
| 11638 | 10 | space_id = UINT32_UNDEFINED; | |
| 11639 | |||
| 11640 | 10 | break; | |
| 11641 | } | ||
| 11642 | } | ||
| 11643 | } else { | ||
| 11644 | 23 | space_id = UINT32_UNDEFINED; | |
| 11645 | } | ||
| 11646 | |||
| 11647 | /* Try the more heavy duty method, as a last resort. */ | ||
| 11648 |
2/2✓ Branch 0 taken 33 times.
✓ Branch 1 taken 78668 times.
|
78701 | if (space_id == UINT32_UNDEFINED) { |
| 11649 | /* If the first page cannot be read properly, then for compressed | ||
| 11650 | tablespaces we don't know where the page boundary starts because | ||
| 11651 | we don't know the page size. */ | ||
| 11652 | |||
| 11653 | 33 | Datafile file; | |
| 11654 | |||
| 11655 |
1/2✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
|
33 | file.set_filepath(filename.c_str()); |
| 11656 | |||
| 11657 |
1/2✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
|
33 | dberr_t err = file.open_read_only(false); |
| 11658 | |||
| 11659 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
|
33 | ut_a(file.is_open()); |
| 11660 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
|
33 | ut_a(err == DB_SUCCESS); |
| 11661 | |||
| 11662 | /* Use the heavier Datafile::find_space_id() method to | ||
| 11663 | find the space id. */ | ||
| 11664 |
1/2✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
|
33 | err = file.find_space_id(); |
| 11665 | |||
| 11666 |
1/2✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
|
33 | if (err == DB_SUCCESS) { |
| 11667 | 33 | space_id = file.space_id(); | |
| 11668 | } | ||
| 11669 | |||
| 11670 |
1/2✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
|
33 | file.close(); |
| 11671 | 33 | } | |
| 11672 | |||
| 11673 | 78701 | return space_id; | |
| 11674 | 78701 | } | |
| 11675 | |||
| 11676 | 9723 | void Fil_system::rename_partition_files(bool revert) { | |
| 11677 | #ifndef UNIV_HOTBACKUP | ||
| 11678 | /* If revert, then we are downgrading after upgrade failure from 5.7 */ | ||
| 11679 |
4/6✓ Branch 0 taken 30 times.
✓ Branch 1 taken 9693 times.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9723 times.
|
9723 | ut_ad(!revert || srv_downgrade_partition_files); |
| 11680 | |||
| 11681 |
2/2✓ Branch 0 taken 9681 times.
✓ Branch 1 taken 42 times.
|
9723 | if (m_old_paths.empty()) { |
| 11682 | 9681 | return; | |
| 11683 | } | ||
| 11684 | |||
| 11685 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | ut_ad(!lower_case_file_system); |
| 11686 | |||
| 11687 |
2/2✓ Branch 0 taken 499 times.
✓ Branch 1 taken 42 times.
|
541 | for (auto &old_path : m_old_paths) { |
| 11688 |
2/4✓ Branch 0 taken 499 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 499 times.
|
499 | ut_ad(Fil_path::has_suffix(IBD, old_path)); |
| 11689 |
2/4✓ Branch 0 taken 499 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 499 times.
|
499 | ut_ad(dict_name::is_partition(old_path)); |
| 11690 | |||
| 11691 |
1/2✓ Branch 0 taken 499 times.
✗ Branch 1 not taken.
|
499 | fil_rename_partition_file(old_path, IBD, revert, false); |
| 11692 | } | ||
| 11693 | #endif /* !UNIV_HOTBACKUP */ | ||
| 11694 | } | ||
| 11695 | |||
| 11696 | 19180 | void Tablespace_dirs::duplicate_check(const Const_iter &start, | |
| 11697 | const Const_iter &end, size_t thread_id, | ||
| 11698 | std::mutex *mutex, Space_id_set *unique, | ||
| 11699 | Space_id_set *duplicates) { | ||
| 11700 | 19180 | size_t count = 0; | |
| 11701 | 19180 | bool printed_msg = false; | |
| 11702 | 19180 | auto start_time = std::chrono::steady_clock::now(); | |
| 11703 | |||
| 11704 |
2/2✓ Branch 0 taken 78701 times.
✓ Branch 1 taken 19180 times.
|
97881 | for (auto it = start; it != end; ++it, ++m_checked) { |
| 11705 |
1/2✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
|
78701 | const std::string filename = it->second; |
| 11706 | 78701 | auto &files = m_dirs[it->first]; | |
| 11707 |
1/2✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
|
78701 | const std::string phy_filename = files.path() + filename; |
| 11708 | |||
| 11709 | space_id_t space_id; | ||
| 11710 | |||
| 11711 |
1/2✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
|
78701 | space_id = Fil_system::get_tablespace_id(phy_filename); |
| 11712 | |||
| 11713 |
2/4✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78701 times.
✗ Branch 3 not taken.
|
78701 | if (space_id != 0 && space_id != dict_sys_t::s_invalid_space_id) { |
| 11714 |
1/2✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
|
78701 | std::lock_guard<std::mutex> guard(*mutex); |
| 11715 | |||
| 11716 |
1/2✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
|
78701 | auto ret = unique->insert(space_id); |
| 11717 | |||
| 11718 | size_t n_files; | ||
| 11719 | |||
| 11720 |
1/2✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
|
78701 | n_files = files.add(space_id, filename); |
| 11721 | |||
| 11722 |
3/4✓ Branch 0 taken 78700 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 78700 times.
|
78701 | if (n_files > 1 || !ret.second) { |
| 11723 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | duplicates->insert(space_id); |
| 11724 | } | ||
| 11725 | |||
| 11726 |
0/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
78701 | } else if (space_id != 0 && |
| 11727 | ✗ | Fil_path::is_undo_tablespace_name(phy_filename)) { | |
| 11728 | ✗ | ib::info(ER_IB_MSG_373) << "Can't determine the undo file tablespace" | |
| 11729 | ✗ | << " ID for '" << phy_filename << "', could be" | |
| 11730 | ✗ | << " an undo truncate in progress"; | |
| 11731 | |||
| 11732 | } else { | ||
| 11733 | ✗ | ib::info(ER_IB_MSG_374) << "Ignoring '" << phy_filename << "' invalid" | |
| 11734 | ✗ | << " tablespace ID in the header"; | |
| 11735 | } | ||
| 11736 | |||
| 11737 | 78701 | ++count; | |
| 11738 | |||
| 11739 |
3/6✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78701 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 78701 times.
|
78701 | if (std::chrono::steady_clock::now() - start_time >= PRINT_INTERVAL) { |
| 11740 | ✗ | ib::info(ER_IB_MSG_375) << "Thread# " << thread_id << " - Checked " | |
| 11741 | ✗ | << count << "/" << (end - start) << " files"; | |
| 11742 | |||
| 11743 | ✗ | start_time = std::chrono::steady_clock::now(); | |
| 11744 | |||
| 11745 | ✗ | printed_msg = true; | |
| 11746 | } | ||
| 11747 | 78701 | } | |
| 11748 | |||
| 11749 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19180 times.
|
19180 | if (printed_msg) { |
| 11750 | ✗ | ib::info(ER_IB_MSG_376) << "Checked " << count << " files"; | |
| 11751 | } | ||
| 11752 | 19180 | } | |
| 11753 | |||
| 11754 | /** Print the duplicate filenames for a tablespce ID to the log | ||
| 11755 | @param[in] duplicates Duplicate tablespace IDs*/ | ||
| 11756 | 1 | void Tablespace_dirs::print_duplicates(const Space_id_set &duplicates) { | |
| 11757 | /* Print the duplicate names to the error log. */ | ||
| 11758 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (auto space_id : duplicates) { |
| 11759 | 1 | Dirs files; | |
| 11760 | |||
| 11761 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (auto &dir : m_dirs) { |
| 11762 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | const auto names = dir.find_by_id(space_id); |
| 11763 | |||
| 11764 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (names == nullptr) { |
| 11765 | ✗ | continue; | |
| 11766 | } | ||
| 11767 | |||
| 11768 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | files.insert(files.end(), names->begin(), names->end()); |
| 11769 | } | ||
| 11770 | |||
| 11771 | /* Fixes the order in the mtr tests. */ | ||
| 11772 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | std::sort(files.begin(), files.end()); |
| 11773 | |||
| 11774 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | ut_a(files.size() > 1); |
| 11775 | |||
| 11776 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | std::ostringstream oss; |
| 11777 | |||
| 11778 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | oss << "Tablespace ID: " << space_id << " = ["; |
| 11779 | |||
| 11780 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (size_t i = 0; i < files.size(); ++i) { |
| 11781 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | oss << "'" << files[i] << "'"; |
| 11782 | |||
| 11783 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (i < files.size() - 1) { |
| 11784 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | oss << ", "; |
| 11785 | } | ||
| 11786 | } | ||
| 11787 | |||
| 11788 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | oss << "]" << std::endl; |
| 11789 | |||
| 11790 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | ib::error(ER_IB_MSG_377) << oss.str(); |
| 11791 | 1 | } | |
| 11792 | 1 | } | |
| 11793 | |||
| 11794 | 1895430 | static bool fil_get_partition_file(const std::string &old_path [[maybe_unused]], | |
| 11795 | ib_file_suffix extn [[maybe_unused]], | ||
| 11796 | std::string &new_path [[maybe_unused]]) { | ||
| 11797 | /* Safe check. Never needed on Windows. */ | ||
| 11798 | #ifdef _WIN32 | ||
| 11799 | return false; | ||
| 11800 | #else /* WIN32 */ | ||
| 11801 | |||
| 11802 | #ifndef UNIV_HOTBACKUP | ||
| 11803 | /* Needed only for case sensitive file system. */ | ||
| 11804 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1895430 times.
|
1895430 | if (lower_case_file_system) { |
| 11805 | ✗ | return false; | |
| 11806 | } | ||
| 11807 | |||
| 11808 | /* Skip if not right file extension. */ | ||
| 11809 |
3/4✓ Branch 0 taken 1895430 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1835236 times.
✓ Branch 3 taken 60194 times.
|
1895430 | if (!Fil_path::has_suffix(extn, old_path)) { |
| 11810 | 1835236 | return false; | |
| 11811 | } | ||
| 11812 | |||
| 11813 | /* Check if partitioned table. */ | ||
| 11814 |
3/4✓ Branch 0 taken 60194 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55353 times.
✓ Branch 3 taken 4841 times.
|
60194 | if (!dict_name::is_partition(old_path)) { |
| 11815 | 55353 | return false; | |
| 11816 | } | ||
| 11817 | |||
| 11818 | 4841 | std::string table_name; | |
| 11819 | /* Get Innodb dictionary name from file path. */ | ||
| 11820 |
2/4✓ Branch 0 taken 4841 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4841 times.
|
4841 | if (!Fil_path::parse_file_path(old_path, extn, table_name)) { |
| 11821 | ✗ | ut_d(ut_error); | |
| 11822 | ut_o(return false); | ||
| 11823 | } | ||
| 11824 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4841 times.
|
4841 | ut_ad(!table_name.empty()); |
| 11825 | |||
| 11826 | /* Rebuild partition table name with lower case. */ | ||
| 11827 |
1/2✓ Branch 0 taken 4841 times.
✗ Branch 1 not taken.
|
4841 | std::string save_name(table_name); |
| 11828 |
1/2✓ Branch 0 taken 4841 times.
✗ Branch 1 not taken.
|
4841 | dict_name::rebuild(table_name); |
| 11829 | |||
| 11830 |
3/4✓ Branch 0 taken 4841 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3905 times.
✓ Branch 3 taken 936 times.
|
4841 | if (save_name.compare(table_name) == 0) { |
| 11831 | 3905 | return false; | |
| 11832 | } | ||
| 11833 | |||
| 11834 | /* Build new partition file name. */ | ||
| 11835 |
1/2✓ Branch 0 taken 936 times.
✗ Branch 1 not taken.
|
936 | new_path = Fil_path::make_new_path(old_path, table_name, extn); |
| 11836 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 936 times.
|
936 | ut_ad(!new_path.empty()); |
| 11837 | #endif /* !UNIV_HOTBACKUP */ | ||
| 11838 | |||
| 11839 | 936 | return true; | |
| 11840 | #endif /* WIN32 */ | ||
| 11841 | 4841 | } | |
| 11842 | |||
| 11843 | #ifndef UNIV_HOTBACKUP | ||
| 11844 | 529 | static void fil_rename_partition_file(const std::string &old_path, | |
| 11845 | ib_file_suffix extn, bool revert, | ||
| 11846 | bool import) { | ||
| 11847 | 529 | std::string new_path; | |
| 11848 | |||
| 11849 |
2/4✓ Branch 0 taken 529 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 529 times.
|
529 | if (!fil_get_partition_file(old_path, extn, new_path)) { |
| 11850 | ✗ | ut_d(ut_error); | |
| 11851 | ut_o(return ); | ||
| 11852 | } | ||
| 11853 | |||
| 11854 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 529 times.
|
529 | ut_ad(!new_path.empty()); |
| 11855 | |||
| 11856 |
1/2✓ Branch 0 taken 529 times.
✗ Branch 1 not taken.
|
529 | bool old_exists = os_file_exists(old_path.c_str()); |
| 11857 |
1/2✓ Branch 0 taken 529 times.
✗ Branch 1 not taken.
|
529 | bool new_exists = os_file_exists(new_path.c_str()); |
| 11858 | |||
| 11859 | static bool print_upgrade = true; | ||
| 11860 | static bool print_downgrade = true; | ||
| 11861 | 529 | bool ret = false; | |
| 11862 | |||
| 11863 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 437 times.
|
529 | if (revert) { |
| 11864 | /* Check if rename is required. */ | ||
| 11865 |
2/4✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 92 times.
|
92 | if (!new_exists || old_exists) { |
| 11866 | ✗ | return; | |
| 11867 | } | ||
| 11868 |
1/2✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
|
92 | ret = os_file_rename(innodb_data_file_key, new_path.c_str(), |
| 11869 | old_path.c_str()); | ||
| 11870 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
|
92 | ut_ad(ret); |
| 11871 | |||
| 11872 |
3/4✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 85 times.
|
92 | if (ret && print_downgrade) { |
| 11873 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | ib::info(ER_IB_MSG_DOWNGRADE_PARTITION_FILE, new_path.c_str(), |
| 11874 | 7 | old_path.c_str()); | |
| 11875 | 7 | print_downgrade = false; | |
| 11876 | } | ||
| 11877 | 92 | return; | |
| 11878 | } | ||
| 11879 | |||
| 11880 | /* Check if rename is required. */ | ||
| 11881 |
2/4✓ Branch 0 taken 437 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 437 times.
|
437 | if (new_exists || !old_exists) { |
| 11882 | ✗ | return; | |
| 11883 | } | ||
| 11884 | |||
| 11885 | ret = | ||
| 11886 |
1/2✓ Branch 0 taken 437 times.
✗ Branch 1 not taken.
|
437 | os_file_rename(innodb_data_file_key, old_path.c_str(), new_path.c_str()); |
| 11887 | |||
| 11888 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 437 times.
|
437 | if (!ret) { |
| 11889 | /* File rename failed. */ | ||
| 11890 | ✗ | ut_d(ut_error); | |
| 11891 | ut_o(return ); | ||
| 11892 | } | ||
| 11893 | |||
| 11894 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 407 times.
|
437 | if (import) { |
| 11895 |
1/2✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
|
30 | ib::info(ER_IB_MSG_UPGRADE_PARTITION_FILE_IMPORT, old_path.c_str(), |
| 11896 | 30 | new_path.c_str()); | |
| 11897 | 30 | return; | |
| 11898 | } | ||
| 11899 | |||
| 11900 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 372 times.
|
407 | if (print_upgrade) { |
| 11901 |
1/2✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
|
35 | ib::info(ER_IB_MSG_UPGRADE_PARTITION_FILE, old_path.c_str(), |
| 11902 | 35 | new_path.c_str()); | |
| 11903 | 35 | print_upgrade = false; | |
| 11904 | } | ||
| 11905 |
2/2✓ Branch 0 taken 407 times.
✓ Branch 1 taken 122 times.
|
529 | } |
| 11906 | #endif /* !UNIV_HOTBACKUP */ | ||
| 11907 | |||
| 11908 | 19433 | void Tablespace_dirs::set_scan_dir(const std::string &in_directory, | |
| 11909 | bool is_undo_dir) { | ||
| 11910 |
1/2✓ Branch 0 taken 19433 times.
✗ Branch 1 not taken.
|
19433 | std::string directory(in_directory); |
| 11911 | |||
| 11912 | 19433 | Fil_path::normalize(directory); | |
| 11913 | |||
| 11914 |
1/2✓ Branch 0 taken 19433 times.
✗ Branch 1 not taken.
|
19433 | add_path(directory, is_undo_dir); |
| 11915 | 19433 | } | |
| 11916 | |||
| 11917 | 86 | void Tablespace_dirs::set_scan_dirs(const std::string &in_directories) { | |
| 11918 |
1/2✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
|
86 | std::string directories(in_directories); |
| 11919 | |||
| 11920 | 86 | Fil_path::normalize(directories); | |
| 11921 | |||
| 11922 | 86 | std::string separators; | |
| 11923 | |||
| 11924 |
1/2✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
|
86 | separators.push_back(FIL_PATH_SEPARATOR); |
| 11925 | |||
| 11926 |
1/2✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
|
86 | add_paths(directories, separators); |
| 11927 | 86 | } | |
| 11928 | |||
| 11929 | /** Discover tablespaces by reading the header from .ibd files. | ||
| 11930 | @return DB_SUCCESS if all goes well */ | ||
| 11931 | 9693 | dberr_t Tablespace_dirs::scan() { | |
| 11932 | 9693 | Scanned_files ibd_files; | |
| 11933 | 9693 | Scanned_files undo_files; | |
| 11934 | 9693 | uint16_t count = 0; | |
| 11935 | 9693 | bool print_msg = false; | |
| 11936 | 9693 | auto start_time = std::chrono::steady_clock::now(); | |
| 11937 | |||
| 11938 | /* Should be trivial to parallelize the scan and ID check. */ | ||
| 11939 |
2/2✓ Branch 0 taken 9887 times.
✓ Branch 1 taken 9693 times.
|
19580 | for (const auto &dir : m_dirs) { |
| 11940 |
1/2✓ Branch 0 taken 9887 times.
✗ Branch 1 not taken.
|
9887 | const auto real_path_dir = dir.root().abs_path(); |
| 11941 | |||
| 11942 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9887 times.
|
9887 | ut_a(Fil_path::is_separator(dir.path().back())); |
| 11943 | |||
| 11944 |
4/8✓ Branch 0 taken 9887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9887 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9887 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9887 times.
✗ Branch 7 not taken.
|
9887 | ib::info(ER_IB_MSG_379) << "Scanning '" << dir.path() << "'"; |
| 11945 | |||
| 11946 | /* Walk the sub-tree of dir. */ | ||
| 11947 | |||
| 11948 |
1/2✓ Branch 0 taken 9887 times.
✗ Branch 1 not taken.
|
9887 | Dir_Walker::walk(real_path_dir, true, [&](const std::string &path) { |
| 11949 | /* If it is a file and the suffix matches ".ibd" | ||
| 11950 | or the undo file name format then store it for | ||
| 11951 | determining the space ID. */ | ||
| 11952 | |||
| 11953 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1894901 times.
|
1894901 | ut_a(path.length() > real_path_dir.length()); |
| 11954 |
2/4✓ Branch 0 taken 1894901 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1894901 times.
|
1894901 | ut_a(Fil_path::get_file_type(path) != OS_FILE_TYPE_DIR); |
| 11955 | |||
| 11956 | /* Check if need to alter partition file names to lower case. */ | ||
| 11957 | 1894901 | std::string new_path; | |
| 11958 | |||
| 11959 |
3/4✓ Branch 0 taken 1894901 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 407 times.
✓ Branch 3 taken 1894494 times.
|
1894901 | if (fil_get_partition_file(path, IBD, new_path)) { |
| 11960 | /* Note all old file names to be renamed. */ | ||
| 11961 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 407 times.
|
407 | ut_ad(!new_path.empty()); |
| 11962 |
1/2✓ Branch 0 taken 407 times.
✗ Branch 1 not taken.
|
407 | fil_system->add_old_file(path); |
| 11963 | |||
| 11964 | } else { | ||
| 11965 |
1/2✓ Branch 0 taken 1894494 times.
✗ Branch 1 not taken.
|
1894494 | new_path.assign(path); |
| 11966 | } | ||
| 11967 | |||
| 11968 | /* Make the filename relative to the directory that was scanned. */ | ||
| 11969 |
1/2✓ Branch 0 taken 1894901 times.
✗ Branch 1 not taken.
|
1894901 | std::string file = new_path.substr(real_path_dir.length()); |
| 11970 | |||
| 11971 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1894899 times.
|
1894901 | if (file.size() <= 4) { |
| 11972 | 2 | return; | |
| 11973 | } | ||
| 11974 | |||
| 11975 | using Value = Scanned_files::value_type; | ||
| 11976 | |||
| 11977 |
4/6✓ Branch 0 taken 1894899 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1894899 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 59665 times.
✓ Branch 5 taken 1835234 times.
|
1894899 | if (Fil_path::has_suffix(IBD, file.c_str())) { |
| 11978 |
2/4✓ Branch 0 taken 59665 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 59665 times.
✗ Branch 3 not taken.
|
59665 | ibd_files.push_back(Value{count, file}); |
| 11979 | |||
| 11980 |
3/4✓ Branch 0 taken 1835234 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19036 times.
✓ Branch 3 taken 1816198 times.
|
1835234 | } else if (Fil_path::is_undo_tablespace_name(file)) { |
| 11981 |
2/4✓ Branch 0 taken 19036 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19036 times.
✗ Branch 3 not taken.
|
19036 | undo_files.push_back(Value{count, file}); |
| 11982 | } | ||
| 11983 | |||
| 11984 |
3/6✓ Branch 0 taken 1894899 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1894899 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1894899 times.
|
1894899 | if (std::chrono::steady_clock::now() - start_time >= PRINT_INTERVAL) { |
| 11985 | ✗ | ib::info(ER_IB_MSG_380) | |
| 11986 | ✗ | << "Files found so far: " << ibd_files.size() << " data files" | |
| 11987 | ✗ | << " and " << undo_files.size() << " undo files"; | |
| 11988 | |||
| 11989 | ✗ | start_time = std::chrono::steady_clock::now(); | |
| 11990 | ✗ | print_msg = true; | |
| 11991 | } | ||
| 11992 |
4/4✓ Branch 0 taken 1894899 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1894899 times.
✓ Branch 3 taken 2 times.
|
1894903 | }); |
| 11993 | |||
| 11994 | 9887 | ++count; | |
| 11995 | 9887 | } | |
| 11996 | |||
| 11997 | /* Rename all old partition files. */ | ||
| 11998 |
1/2✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
|
9693 | fil_system->rename_partition_files(false); |
| 11999 | |||
| 12000 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9693 times.
|
9693 | if (print_msg) { |
| 12001 | ✗ | ib::info(ER_IB_MSG_381) << "Found " << ibd_files.size() << " '.ibd' and " | |
| 12002 | ✗ | << undo_files.size() << " undo files"; | |
| 12003 | } | ||
| 12004 | |||
| 12005 | 9693 | Space_id_set unique; | |
| 12006 | 9693 | Space_id_set duplicates; | |
| 12007 | |||
| 12008 | /* Get the number of additional threads needed to scan the files. */ | ||
| 12009 |
1/2✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
|
9693 | size_t n_threads = fil_get_scan_threads(ibd_files.size()); |
| 12010 | |||
| 12011 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9693 times.
|
9693 | if (n_threads > 0) { |
| 12012 | ✗ | ib::info(ER_IB_MSG_382) | |
| 12013 | ✗ | << "Using " << (n_threads + 1) << " threads to" | |
| 12014 | ✗ | << " scan " << ibd_files.size() << " tablespace files"; | |
| 12015 | } | ||
| 12016 | |||
| 12017 | 9693 | std::mutex m; | |
| 12018 | |||
| 12019 | using std::placeholders::_1; | ||
| 12020 | using std::placeholders::_2; | ||
| 12021 | using std::placeholders::_3; | ||
| 12022 | using std::placeholders::_4; | ||
| 12023 | using std::placeholders::_5; | ||
| 12024 | using std::placeholders::_6; | ||
| 12025 | |||
| 12026 | std::function<void(const Const_iter &, const Const_iter &, size_t, | ||
| 12027 | std::mutex *, Space_id_set *, Space_id_set *)> | ||
| 12028 |
1/2✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
|
9693 | check = std::bind(&Tablespace_dirs::duplicate_check, this, _1, _2, _3, _4, |
| 12029 |
1/2✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
|
9693 | _5, _6); |
| 12030 | |||
| 12031 |
1/2✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
|
9693 | par_for(PFS_NOT_INSTRUMENTED, ibd_files, n_threads, check, &m, &unique, |
| 12032 | &duplicates); | ||
| 12033 | |||
| 12034 |
1/2✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
|
9693 | duplicate_check(undo_files.begin(), undo_files.end(), n_threads, &m, &unique, |
| 12035 | &duplicates); | ||
| 12036 | |||
| 12037 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9693 times.
|
9693 | ut_a(m_checked == ibd_files.size() + undo_files.size()); |
| 12038 | |||
| 12039 |
3/6✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9693 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9693 times.
✗ Branch 5 not taken.
|
29079 | ib::info(ER_IB_MSG_383) << "Completed space ID check of " << m_checked.load() |
| 12040 |
1/2✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
|
9693 | << " files."; |
| 12041 | |||
| 12042 | dberr_t err; | ||
| 12043 | |||
| 12044 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9692 times.
|
9693 | if (!duplicates.empty()) { |
| 12045 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
2 | ib::error(ER_IB_MSG_384) |
| 12046 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | << "Multiple files found for the same tablespace ID:"; |
| 12047 | |||
| 12048 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | print_duplicates(duplicates); |
| 12049 | |||
| 12050 | 1 | err = DB_FAIL; | |
| 12051 | } else { | ||
| 12052 | 9692 | err = DB_SUCCESS; | |
| 12053 | } | ||
| 12054 | |||
| 12055 | 9693 | return err; | |
| 12056 | 9693 | } | |
| 12057 | |||
| 12058 | 19433 | void fil_set_scan_dir(const std::string &directory, bool is_undo_dir) { | |
| 12059 | 19433 | fil_system->set_scan_dir(directory, is_undo_dir); | |
| 12060 | 19433 | } | |
| 12061 | |||
| 12062 | 86 | void fil_set_scan_dirs(const std::string &directories) { | |
| 12063 | 86 | fil_system->set_scan_dirs(directories); | |
| 12064 | 86 | } | |
| 12065 | |||
| 12066 | /** Discover tablespaces by reading the header from .ibd files. | ||
| 12067 | @return DB_SUCCESS if all goes well */ | ||
| 12068 | 9693 | dberr_t fil_scan_for_tablespaces() { return fil_system->scan(); } | |
| 12069 | |||
| 12070 | /** Check if a path is known to InnoDB meaning that it is in or under | ||
| 12071 | one of the four path settings scanned at startup for file discovery. | ||
| 12072 | @param[in] path Path to check | ||
| 12073 | @return true if path is known to InnoDB */ | ||
| 12074 | 15110 | bool fil_path_is_known(const std::string &path) { | |
| 12075 | 15110 | return fil_system->check_path(path); | |
| 12076 | } | ||
| 12077 | |||
| 12078 | /** Get the list of directories that datafiles can reside in. | ||
| 12079 | @return the list of directories 'dir1;dir2;....;dirN' */ | ||
| 12080 | 9693 | std::string fil_get_dirs() { return fil_system->get_dirs(); } | |
| 12081 | |||
| 12082 | /** Free the data structures required for recovery. */ | ||
| 12083 | 9493 | void fil_free_scanned_files() { fil_system->free_scanned_files(); } | |
| 12084 | |||
| 12085 | /** Update the tablespace name. In case, the new name | ||
| 12086 | and old name are same, no update done. | ||
| 12087 | @param[in,out] space tablespace object on which name | ||
| 12088 | will be updated | ||
| 12089 | @param[in] name new name for tablespace */ | ||
| 12090 | 2928 | void fil_space_update_name(fil_space_t *space, const char *name) { | |
| 12091 |
3/6✓ Branch 0 taken 2928 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2928 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2928 times.
✗ Branch 5 not taken.
|
2928 | if (space == nullptr || name == nullptr || space->name == nullptr || |
| 12092 |
2/2✓ Branch 0 taken 2923 times.
✓ Branch 1 taken 5 times.
|
2928 | strcmp(space->name, name) == 0) { |
| 12093 | 2923 | return; | |
| 12094 | } | ||
| 12095 | |||
| 12096 | 5 | dberr_t err = fil_rename_tablespace_by_id(space->id, space->name, name); | |
| 12097 | |||
| 12098 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if (err != DB_SUCCESS) { |
| 12099 | ✗ | ib::warn(ER_IB_MSG_387) << "Tablespace rename '" << space->name << "' to" | |
| 12100 | ✗ | << " '" << name << "' failed!"; | |
| 12101 | } | ||
| 12102 | } | ||
| 12103 | |||
| 12104 | #ifndef UNIV_HOTBACKUP | ||
| 12105 | 72358 | bool Fil_path::is_valid_location(const char *space_name, space_id_t space_id, | |
| 12106 | uint32_t fsp_flags, const std::string &path) { | ||
| 12107 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 72358 times.
|
72358 | ut_ad(!path.empty()); |
| 12108 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 72358 times.
|
72358 | ut_ad(space_name != nullptr); |
| 12109 | |||
| 12110 | /* All files sent to this routine have been found by scanning known | ||
| 12111 | locations. */ | ||
| 12112 |
2/2✓ Branch 0 taken 18903 times.
✓ Branch 1 taken 53455 times.
|
72358 | ib_file_suffix type = (fsp_is_undo_tablespace(space_id) ? IBU : IBD); |
| 12113 | |||
| 12114 |
2/2✓ Branch 0 taken 53455 times.
✓ Branch 1 taken 18903 times.
|
72358 | if (type == IBD) { |
| 12115 |
1/2✓ Branch 0 taken 53455 times.
✗ Branch 1 not taken.
|
53455 | size_t dirname_len = dirname_length(path.c_str()); |
| 12116 |
1/2✓ Branch 0 taken 53455 times.
✗ Branch 1 not taken.
|
53455 | Fil_path dirpath(path.c_str(), dirname_len, true); |
| 12117 | |||
| 12118 | 53455 | bool is_shared = fsp_is_shared_tablespace(fsp_flags); | |
| 12119 |
1/2✓ Branch 0 taken 53455 times.
✗ Branch 1 not taken.
|
53455 | bool under_datadir = MySQL_datadir_path.is_ancestor(dirpath); |
| 12120 | |||
| 12121 |
2/2✓ Branch 0 taken 9832 times.
✓ Branch 1 taken 43623 times.
|
53455 | if (is_shared) { |
| 12122 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9832 times.
|
9832 | if (under_datadir) { |
| 12123 | ✗ | ib::error(ER_IB_MSG_GENERAL_TABLESPACE_UNDER_DATADIR, path.c_str()); | |
| 12124 | ✗ | return false; | |
| 12125 | } | ||
| 12126 | } else { | ||
| 12127 | /* file-per-table */ | ||
| 12128 | bool in_datadir = | ||
| 12129 |
3/4✓ Branch 0 taken 43476 times.
✓ Branch 1 taken 147 times.
✓ Branch 2 taken 147 times.
✗ Branch 3 not taken.
|
43623 | (under_datadir ? false : MySQL_datadir_path.is_same_as(dirpath)); |
| 12130 | |||
| 12131 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43623 times.
|
43623 | if (in_datadir) { |
| 12132 | ✗ | ib::error(ER_IB_MSG_IMPLICIT_TABLESPACE_IN_DATADIR, path.c_str()); | |
| 12133 | ✗ | return false; | |
| 12134 | } | ||
| 12135 | |||
| 12136 | /* Make sure that the last directory of an implicit tablespace is a | ||
| 12137 | filesystem charset version of the schema name. */ | ||
| 12138 |
3/4✓ Branch 0 taken 43623 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 198 times.
✓ Branch 3 taken 43425 times.
|
43623 | if (!is_valid_location_within_db(space_name, path)) { |
| 12139 |
1/2✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
|
198 | ib::error(ER_IB_MSG_INVALID_LOCATION_WRONG_DB, path.c_str(), |
| 12140 | space_name); | ||
| 12141 | 198 | return false; | |
| 12142 | } | ||
| 12143 | } | ||
| 12144 |
2/2✓ Branch 0 taken 53257 times.
✓ Branch 1 taken 198 times.
|
53455 | } |
| 12145 | |||
| 12146 | 72160 | return true; | |
| 12147 | } | ||
| 12148 | |||
| 12149 | 43623 | bool Fil_path::is_valid_location_within_db(const char *space_name, | |
| 12150 | const std::string &path) { | ||
| 12151 | /* Strip off the basename to reduce the path to a directory. */ | ||
| 12152 |
1/2✓ Branch 0 taken 43623 times.
✗ Branch 1 not taken.
|
43623 | std::string dirpath{path}; |
| 12153 | 43623 | auto pos = dirpath.find_last_of(SEPARATOR); | |
| 12154 |
1/2✓ Branch 0 taken 43623 times.
✗ Branch 1 not taken.
|
43623 | dirpath.resize(pos); |
| 12155 | |||
| 12156 | /* Only implicit tablespaces are sent to this routine. | ||
| 12157 | They are always prefixed by `schema/`. */ | ||
| 12158 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43623 times.
|
43623 | ut_ad(pos != std::string::npos); |
| 12159 | |||
| 12160 | /* Get the subdir that the file is in. */ | ||
| 12161 | 43623 | pos = dirpath.find_last_of(SEPARATOR); | |
| 12162 | std::string db_dir = (pos == std::string::npos) | ||
| 12163 | ? dirpath | ||
| 12164 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 43623 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 43623 times.
✗ Branch 5 not taken.
|
43623 | : dirpath.substr(pos + 1, dirpath.length()); |
| 12165 | |||
| 12166 | /* Convert to lowercase if necessary. */ | ||
| 12167 |
2/4✓ Branch 0 taken 43623 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 43623 times.
|
43623 | if (innobase_get_lower_case_table_names() == 2) { |
| 12168 | ✗ | Fil_path::convert_to_lower_case(db_dir); | |
| 12169 | } | ||
| 12170 | |||
| 12171 | /* Make sure the db_dir matches the schema name. | ||
| 12172 | db_dir is in filesystem charset and space_name is usually in the | ||
| 12173 | system charset. | ||
| 12174 | |||
| 12175 | The problem here is that the system charset version of a schema or | ||
| 12176 | table name may contain a '/' and the tablespace name we were sent | ||
| 12177 | is a combination of the two with '/' as a delimiter. | ||
| 12178 | For example `my/schema` + `my/table` == `my/schema/my/table` | ||
| 12179 | |||
| 12180 | Search the space_name string backwards until we find the db name that | ||
| 12181 | matches the schema name from the path. */ | ||
| 12182 | |||
| 12183 |
1/2✓ Branch 0 taken 43623 times.
✗ Branch 1 not taken.
|
43623 | std::string name(space_name); |
| 12184 | 43623 | pos = name.find_last_of(SEPARATOR); | |
| 12185 |
1/2✓ Branch 0 taken 43842 times.
✗ Branch 1 not taken.
|
43842 | while (pos < std::string::npos) { |
| 12186 |
1/2✓ Branch 0 taken 43842 times.
✗ Branch 1 not taken.
|
43842 | name.resize(pos); |
| 12187 |
1/2✓ Branch 0 taken 43842 times.
✗ Branch 1 not taken.
|
43842 | std::string temp = name; |
| 12188 |
2/2✓ Branch 0 taken 43414 times.
✓ Branch 1 taken 428 times.
|
43842 | if (temp == db_dir) { |
| 12189 | 43414 | return true; | |
| 12190 | } | ||
| 12191 | |||
| 12192 | /* Convert to filename charset and compare again. */ | ||
| 12193 |
1/2✓ Branch 0 taken 428 times.
✗ Branch 1 not taken.
|
428 | Fil_path::convert_to_filename_charset(temp); |
| 12194 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 417 times.
|
428 | if (temp == db_dir) { |
| 12195 | 11 | return true; | |
| 12196 | } | ||
| 12197 | |||
| 12198 | /* Still no match, iterate through the next SEPARATOR. */ | ||
| 12199 | 417 | pos = name.find_last_of(SEPARATOR); | |
| 12200 | |||
| 12201 | /* If end of string is hit, there is no match. */ | ||
| 12202 |
2/2✓ Branch 0 taken 198 times.
✓ Branch 1 taken 219 times.
|
417 | if (pos == std::string::npos) { |
| 12203 | 198 | return false; | |
| 12204 | } | ||
| 12205 |
2/2✓ Branch 0 taken 219 times.
✓ Branch 1 taken 43623 times.
|
43842 | } |
| 12206 | |||
| 12207 | ✗ | return true; | |
| 12208 | 43623 | } | |
| 12209 | |||
| 12210 | /** Convert filename to the file system charset format. | ||
| 12211 | @param[in,out] name Filename to convert */ | ||
| 12212 | 428 | void Fil_path::convert_to_filename_charset(std::string &name) { | |
| 12213 | 428 | uint errors = 0; | |
| 12214 | char old_name[MAX_TABLE_NAME_LEN + 20]; | ||
| 12215 | char filename[MAX_TABLE_NAME_LEN + 20]; | ||
| 12216 | |||
| 12217 | 428 | strncpy(filename, name.c_str(), sizeof(filename) - 1); | |
| 12218 | 428 | strncpy(old_name, filename, sizeof(old_name)); | |
| 12219 | |||
| 12220 |
1/2✓ Branch 0 taken 428 times.
✗ Branch 1 not taken.
|
428 | innobase_convert_to_filename_charset(filename, old_name, MAX_TABLE_NAME_LEN); |
| 12221 | |||
| 12222 |
1/2✓ Branch 0 taken 428 times.
✗ Branch 1 not taken.
|
428 | if (errors == 0) { |
| 12223 |
1/2✓ Branch 0 taken 428 times.
✗ Branch 1 not taken.
|
428 | name.assign(filename); |
| 12224 | } | ||
| 12225 | 428 | } | |
| 12226 | |||
| 12227 | /** Convert to lower case using the file system charset. | ||
| 12228 | @param[in,out] path Filepath to convert */ | ||
| 12229 | ✗ | void Fil_path::convert_to_lower_case(std::string &path) { | |
| 12230 | char lc_path[MAX_TABLE_NAME_LEN + 20]; | ||
| 12231 | |||
| 12232 | ✗ | ut_ad(path.length() < sizeof(lc_path) - 1); | |
| 12233 | |||
| 12234 | ✗ | strncpy(lc_path, path.c_str(), sizeof(lc_path) - 1); | |
| 12235 | |||
| 12236 | ✗ | innobase_casedn_path(lc_path); | |
| 12237 | |||
| 12238 | ✗ | path.assign(lc_path); | |
| 12239 | } | ||
| 12240 | |||
| 12241 | 560118 | void fil_purge() { fil_system->purge(); } | |
| 12242 | |||
| 12243 | 52927 | size_t fil_count_undo_deleted(space_id_t undo_num) { | |
| 12244 | 52927 | return fil_system->count_undo_deleted(undo_num); | |
| 12245 | } | ||
| 12246 | |||
| 12247 | #endif /* !UNIV_HOTBACKUP */ | ||
| 12248 | |||
| 12249 | #define PAGE_TYPE(x) \ | ||
| 12250 | case x: \ | ||
| 12251 | return #x; | ||
| 12252 | |||
| 12253 | 12423 | const char *fil_get_page_type_str(page_type_t type) noexcept { | |
| 12254 |
13/33✓ Branch 0 taken 581 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 182 times.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10915 times.
✓ Branch 7 taken 39 times.
✓ Branch 8 taken 333 times.
✓ Branch 9 taken 21 times.
✓ Branch 10 taken 107 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 163 times.
✓ Branch 18 taken 16 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✓ Branch 24 taken 9 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✓ Branch 30 taken 2 times.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
|
12423 | switch (type) { |
| 12255 | 581 | PAGE_TYPE(FIL_PAGE_INDEX); | |
| 12256 | ✗ | PAGE_TYPE(FIL_PAGE_RTREE); | |
| 12257 | 17 | PAGE_TYPE(FIL_PAGE_SDI); | |
| 12258 | 182 | PAGE_TYPE(FIL_PAGE_UNDO_LOG); | |
| 12259 | 38 | PAGE_TYPE(FIL_PAGE_INODE); | |
| 12260 | ✗ | PAGE_TYPE(FIL_PAGE_IBUF_FREE_LIST); | |
| 12261 | 10915 | PAGE_TYPE(FIL_PAGE_TYPE_ALLOCATED); | |
| 12262 | 39 | PAGE_TYPE(FIL_PAGE_IBUF_BITMAP); | |
| 12263 | 333 | PAGE_TYPE(FIL_PAGE_TYPE_SYS); | |
| 12264 | 21 | PAGE_TYPE(FIL_PAGE_TYPE_TRX_SYS); | |
| 12265 | 107 | PAGE_TYPE(FIL_PAGE_TYPE_FSP_HDR); | |
| 12266 | ✗ | PAGE_TYPE(FIL_PAGE_TYPE_XDES); | |
| 12267 | ✗ | PAGE_TYPE(FIL_PAGE_TYPE_BLOB); | |
| 12268 | ✗ | PAGE_TYPE(FIL_PAGE_TYPE_ZBLOB); | |
| 12269 | ✗ | PAGE_TYPE(FIL_PAGE_TYPE_ZBLOB2); | |
| 12270 | ✗ | PAGE_TYPE(FIL_PAGE_TYPE_UNKNOWN); | |
| 12271 | ✗ | PAGE_TYPE(FIL_PAGE_COMPRESSED); | |
| 12272 | 163 | PAGE_TYPE(FIL_PAGE_ENCRYPTED); | |
| 12273 | 16 | PAGE_TYPE(FIL_PAGE_COMPRESSED_AND_ENCRYPTED); | |
| 12274 | ✗ | PAGE_TYPE(FIL_PAGE_ENCRYPTED_RTREE); | |
| 12275 | ✗ | PAGE_TYPE(FIL_PAGE_SDI_BLOB); | |
| 12276 | ✗ | PAGE_TYPE(FIL_PAGE_SDI_ZBLOB); | |
| 12277 | ✗ | PAGE_TYPE(FIL_PAGE_TYPE_LOB_INDEX); | |
| 12278 | ✗ | PAGE_TYPE(FIL_PAGE_TYPE_LOB_DATA); | |
| 12279 | 9 | PAGE_TYPE(FIL_PAGE_TYPE_LOB_FIRST); | |
| 12280 | ✗ | PAGE_TYPE(FIL_PAGE_TYPE_ZLOB_FIRST); | |
| 12281 | ✗ | PAGE_TYPE(FIL_PAGE_TYPE_ZLOB_DATA); | |
| 12282 | ✗ | PAGE_TYPE(FIL_PAGE_TYPE_ZLOB_INDEX); | |
| 12283 | ✗ | PAGE_TYPE(FIL_PAGE_TYPE_ZLOB_FRAG); | |
| 12284 | ✗ | PAGE_TYPE(FIL_PAGE_TYPE_ZLOB_FRAG_ENTRY); | |
| 12285 | 2 | PAGE_TYPE(FIL_PAGE_TYPE_RSEG_ARRAY); | |
| 12286 | ✗ | PAGE_TYPE(FIL_PAGE_TYPE_LEGACY_DBLWR); | |
| 12287 | } | ||
| 12288 | ✗ | ut_d(ut_error); | |
| 12289 | ut_o(return "UNKNOWN"); | ||
| 12290 | } | ||
| 12291 | |||
| 12292 | 14 | bool fil_is_page_type_valid(page_type_t type) noexcept { | |
| 12293 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
|
14 | if (fil_page_type_is_index(type)) { |
| 12294 | 2 | return true; | |
| 12295 | } | ||
| 12296 | |||
| 12297 |
2/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
|
12 | if (type <= FIL_PAGE_TYPE_LAST && type != FIL_PAGE_TYPE_UNUSED) { |
| 12298 | 12 | return true; | |
| 12299 | } | ||
| 12300 | |||
| 12301 | ✗ | ut_d(ut_error); | |
| 12302 | ut_o(return false); | ||
| 12303 | } | ||
| 12304 | |||
| 12305 | ✗ | std::ostream &Fil_page_header::print(std::ostream &out) const noexcept { | |
| 12306 | /* Print the header information in the order it is stored. */ | ||
| 12307 | ✗ | out << "[Fil_page_header: FIL_PAGE_OFFSET=" << get_page_no() | |
| 12308 | ✗ | << ", FIL_PAGE_TYPE=" << get_page_type() | |
| 12309 | ✗ | << ", FIL_PAGE_SPACE_ID=" << get_space_id() << "]"; | |
| 12310 | ✗ | return out; | |
| 12311 | } | ||
| 12312 | |||
| 12313 | 21209 | space_id_t Fil_page_header::get_space_id() const noexcept { | |
| 12314 | 21209 | return mach_read_from_4(m_frame + FIL_PAGE_SPACE_ID); | |
| 12315 | } | ||
| 12316 | |||
| 12317 | 21209 | page_no_t Fil_page_header::get_page_no() const noexcept { | |
| 12318 | 21209 | return mach_read_from_4(m_frame + FIL_PAGE_OFFSET); | |
| 12319 | } | ||
| 12320 | |||
| 12321 | ✗ | uint16_t Fil_page_header::get_page_type() const noexcept { | |
| 12322 | ✗ | return mach_read_from_2(m_frame + FIL_PAGE_TYPE); | |
| 12323 | } | ||
| 12324 | |||
| 12325 | 64063460 | fil_node_t *fil_space_t::get_file_node(page_no_t *page_no) noexcept { | |
| 12326 |
2/2✓ Branch 0 taken 18705 times.
✓ Branch 1 taken 64044935 times.
|
64063460 | if (files.size() > 1) { |
| 12327 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 18705 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18705 times.
|
18705 | ut_a(id == TRX_SYS_SPACE || purpose == FIL_TYPE_TEMPORARY); |
| 12328 | |||
| 12329 |
1/2✓ Branch 0 taken 30517 times.
✗ Branch 1 not taken.
|
30517 | for (auto &f : files) { |
| 12330 |
2/2✓ Branch 0 taken 18705 times.
✓ Branch 1 taken 11812 times.
|
30517 | if (f.size > *page_no) { |
| 12331 | 18705 | return &f; | |
| 12332 | } | ||
| 12333 | 11812 | *page_no -= f.size; | |
| 12334 | } | ||
| 12335 | |||
| 12336 |
2/2✓ Branch 0 taken 64045027 times.
✓ Branch 1 taken 36 times.
|
64044935 | } else if (!files.empty()) { |
| 12337 | 64045027 | fil_node_t &f = files.front(); | |
| 12338 | |||
| 12339 |
8/8✓ Branch 0 taken 14532677 times.
✓ Branch 1 taken 49512688 times.
✓ Branch 2 taken 14532141 times.
✓ Branch 3 taken 536 times.
✓ Branch 4 taken 64043870 times.
✓ Branch 5 taken 959 times.
✓ Branch 6 taken 64044442 times.
✓ Branch 7 taken 923 times.
|
64045046 | if ((fsp_is_ibd_tablespace(id) && f.size == 0) || f.size > *page_no) { |
| 12340 | /* We do not know the size of a single-table tablespace | ||
| 12341 | before we open the file */ | ||
| 12342 | 64044442 | return &f; | |
| 12343 | } | ||
| 12344 | /* The page is outside the current bounds of the file. We should not assert | ||
| 12345 | here as we could be loading pages in buffer pool from dump file having pages | ||
| 12346 | from dropped tablespaces. Specifically, for undo tablespace it is possible | ||
| 12347 | to re-use the dropped space ID and the page could be out of bound. We need | ||
| 12348 | to ignore such cases. */ | ||
| 12349 | } | ||
| 12350 | |||
| 12351 | 959 | return nullptr; | |
| 12352 | } | ||
| 12353 | |||
| 12354 | 81889960 | bool fil_space_t::is_deleted() const { | |
| 12355 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 81890445 times.
|
81889960 | ut_ad(fil_system->shard_by_id(id)->mutex_owned()); |
| 12356 | 81890445 | return m_deleted; | |
| 12357 | } | ||
| 12358 | |||
| 12359 | 3346224552 | bool fil_space_t::was_not_deleted() const { | |
| 12360 | /* This is not a critical assertion - if you have this mutex, then possibly | ||
| 12361 | you want to call !is_deleted(). */ | ||
| 12362 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1312725881 times.
|
3346224552 | ut_ad(!fil_system->shard_by_id(id)->mutex_owned()); |
| 12363 | 1312725881 | return !m_deleted; | |
| 12364 | } | ||
| 12365 | |||
| 12366 | #ifndef UNIV_HOTBACKUP | ||
| 12367 | 35198660 | uint32_t fil_space_t::get_current_version() const { | |
| 12368 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35199423 times.
|
35198660 | ut_ad(fil_system->shard_by_id(id)->mutex_owned()); |
| 12369 | 35199423 | return m_version; | |
| 12370 | } | ||
| 12371 | 3396635133 | uint32_t fil_space_t::get_recent_version() const { | |
| 12372 | /* This is not a critical assertion - if you have this mutex, then possibly | ||
| 12373 | you want to call get_current_version(). */ | ||
| 12374 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1294534164 times.
|
3396635133 | ut_ad(!fil_system->shard_by_id(id)->mutex_owned()); |
| 12375 | 1294534164 | return m_version; | |
| 12376 | } | ||
| 12377 | 864131 | bool fil_space_t::has_no_references() const { | |
| 12378 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 864131 times.
|
864131 | ut_ad(fil_system->shard_by_id(id)->mutex_owned()); |
| 12379 | 1728262 | return m_n_ref_count.load() == 0; | |
| 12380 | } | ||
| 12381 | 2873 | size_t fil_space_t::get_reference_count() const { | |
| 12382 | /* This should be only called on server shutdown. */ | ||
| 12383 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2873 times.
|
2873 | ut_ad(fil_system->shard_by_id(id)->mutex_owned()); |
| 12384 | 5746 | return m_n_ref_count.load(); | |
| 12385 | } | ||
| 12386 | |||
| 12387 | #endif /* !UNIV_HOTBACKUP */ | ||
| 12388 | |||
| 12389 | 187505 | void fil_space_t::set_deleted() { | |
| 12390 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 187505 times.
|
187505 | ut_ad(fil_system->shard_by_id(id)->mutex_owned()); |
| 12391 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 187505 times.
|
187505 | ut_a(files.size() == 1); |
| 12392 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 187505 times.
|
187505 | ut_a(n_pending_ops == 0); |
| 12393 | |||
| 12394 | #ifndef UNIV_HOTBACKUP | ||
| 12395 | 187505 | bump_version(); | |
| 12396 | |||
| 12397 | 187505 | m_deleted = true; | |
| 12398 | #endif /* !UNIV_HOTBACKUP */ | ||
| 12399 | 187505 | } | |
| 12400 | |||
| 12401 | #ifndef UNIV_HOTBACKUP | ||
| 12402 | |||
| 12403 | 266880 | void fil_space_t::bump_version() { | |
| 12404 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 266880 times.
|
266880 | ut_ad(fil_system->shard_by_id(id)->mutex_owned()); |
| 12405 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 266879 times.
|
266880 | ut_a(files.size() == 1); |
| 12406 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 266879 times.
|
266879 | ut_a(n_pending_ops == 0); |
| 12407 | |||
| 12408 | /* Bump the version. This will make all pages in buffer pool that reference | ||
| 12409 | the current space version to be stale and freed on first encounter. */ | ||
| 12410 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 266879 times.
|
266879 | ut_a(stop_new_ops); |
| 12411 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 266879 times.
|
266879 | ut_a(!m_deleted); |
| 12412 | |||
| 12413 | 266879 | ++m_version; | |
| 12414 | 266880 | } | |
| 12415 | |||
| 12416 | /** Mark space as corrupt | ||
| 12417 | @param space_id space id */ | ||
| 12418 | ✗ | void fil_space_set_corrupt(space_id_t space_id) { | |
| 12419 | ✗ | auto *const shard = fil_system->shard_by_id(space_id); | |
| 12420 | |||
| 12421 | ✗ | shard->mutex_acquire(); | |
| 12422 | |||
| 12423 | ✗ | auto *const space = shard->get_space_by_id(space_id); | |
| 12424 | |||
| 12425 | ✗ | if (space) space->is_corrupt = true; | |
| 12426 | |||
| 12427 | ✗ | shard->mutex_release(); | |
| 12428 | } | ||
| 12429 | |||
| 12430 | 9573 | void fil_system_acquire() { | |
| 12431 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9573 times.
|
9573 | ut_ad(fil_system); |
| 12432 | 9573 | fil_system->mutex_acquire_all(); | |
| 12433 | 9573 | } | |
| 12434 | |||
| 12435 | 9573 | void fil_system_release() { | |
| 12436 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9573 times.
|
9573 | ut_ad(fil_system); |
| 12437 | 9573 | fil_system->mutex_release_all(); | |
| 12438 | 9573 | } | |
| 12439 | |||
| 12440 | 2 | void fil_lock_shard_by_id(space_id_t space_id) { | |
| 12441 | 2 | auto *const shard = fil_system->shard_by_id(space_id); | |
| 12442 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | ut_ad(shard); |
| 12443 | 2 | shard->mutex_acquire(); | |
| 12444 | 2 | } | |
| 12445 | |||
| 12446 | 2 | void fil_unlock_shard_by_id(space_id_t space_id) { | |
| 12447 | 2 | auto *const shard = fil_system->shard_by_id(space_id); | |
| 12448 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | ut_ad(shard); |
| 12449 | 2 | shard->mutex_release(); | |
| 12450 | 2 | } | |
| 12451 | |||
| 12452 | #endif /* !UNIV_HOTBACKUP */ | ||
| 12453 |